PLearn 0.1
Variable.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // PLearn (A C++ Machine Learning Library)
00004 // Copyright (C) 1998 Pascal Vincent
00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal
00006 //
00007 
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions are met:
00010 // 
00011 //  1. Redistributions of source code must retain the above copyright
00012 //     notice, this list of conditions and the following disclaimer.
00013 // 
00014 //  2. Redistributions in binary form must reproduce the above copyright
00015 //     notice, this list of conditions and the following disclaimer in the
00016 //     documentation and/or other materials provided with the distribution.
00017 // 
00018 //  3. The name of the authors may not be used to endorse or promote
00019 //     products derived from this software without specific prior written
00020 //     permission.
00021 // 
00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 // 
00033 // This file is part of the PLearn library. For more information on the PLearn
00034 // library, go to the PLearn Web site at www.plearn.org
00035 
00036 
00037  
00038 
00039 /* *******************************************************      
00040  * $Id: Variable.cc 9774 2008-12-11 21:06:26Z nouiz $
00041  * This file is part of the PLearn library.
00042  ******************************************************* */
00043 
00046 #include "Var.h"
00047 #include "VarArray.h"
00048 #include "Func.h"
00049 
00050 #include "VarElementVariable.h"
00051 #include "VarRowVariable.h"
00052 #include "SubMatVariable.h"
00053 #include "SubMatTransposeVariable.h"
00054 #include "SourceVariable.h"
00055 #include "PlusScalarVariable.h"
00056 #include "TimesConstantVariable.h"
00057 #include "Var_operators.h"
00058 
00059 //#include "Var_utils.h"
00060 
00061 namespace PLearn {
00062 using namespace std;
00063 
00064 // To be able to use varDeepCopyField.
00065 // extern void varDeepCopyField(Var& field, CopiesMap& copies);
00066 
00069 Var::Var() :PP<Variable>(0) {}
00070 Var::Var(Variable* v) :PP<Variable>(v) {}
00071 Var::Var(Variable* v, const char* name) :PP<Variable>(v) { ptr->setName(name); }
00072 Var::Var(const Var& other) :PP<Variable>(other) {}
00073 Var::Var(const Var& other, const char* name) :PP<Variable>(other) { ptr->setName(name); }
00074 Var::Var(const Var &other, const string &name) : PP<Variable>(other) { ptr->setName(name); }
00075 
00076 Var::Var(int the_length, const char* name) 
00077     :PP<Variable>(new SourceVariable(the_length,1)) 
00078 { ptr->setName(name); }
00079 
00080 Var::Var(int the_length, const string &name)
00081     : PP<Variable>(new SourceVariable(the_length, 1))
00082 { ptr->setName(name); }
00083 
00084 Var::Var(int the_length, int the_width)
00085     :PP<Variable>(new SourceVariable(the_length,the_width)) {}
00086 
00087 Var::Var(int the_length, int the_width, const char* name)
00088     :PP<Variable>(new SourceVariable(the_length,the_width)) { ptr->setName(name); }
00089 
00090 Var::Var(int the_length, int the_width, const string &name)
00091     : PP<Variable>(new SourceVariable(the_length, the_width))
00092 { ptr->setName(name); }
00093 
00094 Var::Var(const Vec& v, bool vertical) 
00095     :PP<Variable>(new SourceVariable(v,vertical)) 
00096 {}
00097 
00098 Var::Var(const Mat& m) 
00099     :PP<Variable>(new SourceVariable(m))
00100 {}
00101 
00103 // length //
00105 int Var::length() const
00106 { return (*this)->length(); }
00107 
00109 // width //
00111 int Var::width() const
00112 { return (*this)->width(); }
00113 
00115 // [] // 
00117 Var Var::operator[](int i) const
00118 {
00119     if(width()==1)
00120         return operator()(i,0);
00121     else if(length()==1)
00122         return operator()(0,i);
00123     PLERROR("You shouldnt use operator[](int i) to access a matrix variable, consider using operator() instead");
00124     return Var();
00125 }
00126 
00127 Var Var::operator[](Var index) const
00128 { 
00129     if (!ptr->isVec())
00130         PLERROR("In Var::operator[](Var index) - You should not use this "
00131                 "operator to get the row of a matrix Var, but "
00132                 "operator()(Var index)");
00133     return new VarElementVariable(*this, index); 
00134 }
00135 
00137 // subMat //
00139 Var Var::subMat(int i, int j, int sublength, int subwidth, bool do_transpose) const
00140 { 
00141     if(do_transpose)
00142         return new SubMatTransposeVariable(*this, i, j, sublength, subwidth);
00143     else 
00144         return new SubMatVariable(*this, i, j, sublength, subwidth);
00145 }
00146 
00147 Var Var::subVec(int start, int len, bool transpose) const
00148 {
00149     if(width()==1)
00150         return subMat(start,0,len,1,transpose);
00151     else if(length()==1)
00152         return subMat(0,start,1,len,transpose);
00153 
00154     PLERROR("In Variable::subVec variable is not a vec (single column or single row)");
00155     return Var();
00156 }
00157 
00158 Var Var::operator()(Var index) const
00159 { return new VarRowVariable(*this,index); }
00160 
00161 Var Var::operator()(Var i, Var j) const
00162 { return new VarElementVariable(*this, new PlusScalarVariable(j, new TimesConstantVariable(i,(real)width()))); }
00163 
00164 void Var::operator=(real f)
00165 { 
00166     if (!isNull())
00167         (*this)->value.fill(f);
00168     else
00169         PLERROR("Var::operator= called on null Var");
00170 }
00171 
00172 void Var::operator=(const Vec& v)
00173 { 
00174     if (!isNull())
00175         (*this)->value << v;
00176     else
00177         PLERROR("Var::operator= called on null Var");
00178 }
00179 
00180 void Var::operator=(const Mat& m)
00181 { 
00182     if (!isNull())
00183         (*this)->matValue << m;
00184     else
00185         PLERROR("Var::operator= called on null Var");
00186 }
00187 
00188 int Variable::nvars = 0;
00189 
00190 Variable::Variable(int thelength, int thewidth, bool call_build_):
00191     inherited(call_build_),
00192     varnum(++nvars), marked(false), varname(""),  
00193     allows_partial_update(false), gradient_status(0),
00194     matValue(thelength,thewidth), matGradient(thelength,thewidth), 
00195     min_value(-FLT_MAX), max_value(FLT_MAX), diaghessiandata(0), rvaluedata(0),
00196     dont_bprop_here(false)
00197 {
00198     value = matValue.toVec();
00199     gradient = matGradient.toVec();
00200     if(value.getStorage())
00201         valuedata = value.data();
00202     else
00203         valuedata = 0;
00204     if (gradient.getStorage())
00205         gradientdata = gradient.data();
00206     else
00207         gradientdata = 0;
00208     if (call_build_)
00209         build_();
00210 }
00211 
00212 Variable::Variable(const Mat& m, bool call_build_)
00213     :varnum(++nvars), marked(false), varname(""),  
00214      allows_partial_update(false), gradient_status(0),
00215      matValue(m), matGradient(m.length(),m.width()), 
00216      min_value(-FLT_MAX), max_value(FLT_MAX), diaghessiandata(0), rvaluedata(0),
00217      dont_bprop_here(false)
00218 {
00219     if(!m.isCompact())
00220         PLERROR("To be able to construct a Var that views the same data as a Mat m, the Mat must be compact (width()==mod()). Maybe you can use m.copy() instead of m?");
00221     value = matValue.toVec();
00222     gradient = matGradient.toVec();
00223     if(value.getStorage())
00224         valuedata = value.data();
00225     else
00226         valuedata = 0;
00227     if (gradient.getStorage())
00228         gradientdata = gradient.data();
00229     else
00230         gradientdata = 0;
00231     if (call_build_)
00232         build_();
00233 }
00234 
00235 // shallow copy (same as default copy constructor, except varnum is set to ++nvars.
00236 Variable::Variable(const Variable& v)
00237     :varnum(++nvars), marked(false), varname(v.getName()), 
00238      allows_partial_update(v.allows_partial_update), gradient_status(v.gradient_status),
00239      value(v.value), gradient(v.gradient), 
00240      matValue(v.matValue),matGradient(v.matGradient),
00241      valuedata(v.valuedata), gradientdata(v.gradientdata),
00242      min_value(v.min_value),max_value(v.max_value),
00243      g(v.g), diaghessian(v.diaghessian), diaghessiandata(v.diaghessiandata),
00244      rvaluedata(v.rvaluedata), dont_bprop_here(v.dont_bprop_here)
00245 {}
00246 
00247 
00249 // declareOptions //
00251 void Variable::declareOptions(OptionList& ol)
00252 {
00253     declareOption(ol, "varname", &Variable::varname, OptionBase::buildoption, 
00254                   "An (optional) name for the variable\n");
00255 
00256     declareOption(ol, "value", &Variable::matValue, OptionBase::learntoption, 
00257                   "Current value of the variable\n");
00258 
00259     declareOption(ol, "min_value", &Variable::min_value, OptionBase::buildoption, 
00260                   "minimum value of the variable\n");
00261 
00262     declareOption(ol, "max_value", &Variable::max_value, OptionBase::buildoption, 
00263                   "maximum value of the variable\n");
00264 
00265     /*
00266       declareOption(ol, "gradient", &Variable::matGradient, OptionBase::learntoption, 
00267       "Current gradient of the variable\n");
00268     */
00269 
00270     inherited::declareOptions(ol);
00271 }
00272 
00274 // declareMethods //
00276 void Variable::declareMethods(RemoteMethodMap& rmm)
00277 {
00278     // Insert a backpointer to remote methods; note that this
00279     // different than for declareOptions()
00280     rmm.inherited(inherited::_getRemoteMethodMap_());
00281 
00282     declareMethod(
00283             rmm, "fillValue", &Variable::fillValue,
00284             (BodyDoc("Fill value with the given constant"),
00285              ArgDoc ("val", "Value to fill with")));
00286 
00287     declareMethod(
00288             rmm, "setValueSubMat", &Variable::setValueSubMat,
00289             (BodyDoc("Replace a sub-matrix of the value with the given data"),
00290              ArgDoc ("submat", "Data to set (as a matrix)"),
00291              ArgDoc ("istart", "Row where 'submat' is inserted"),
00292              ArgDoc ("jstart", "Column where 'submat' is inserted")));
00293 
00294     declareMethod(
00295             rmm, "setMinValue", &Variable::setMinValue,
00296             (BodyDoc("Set box constraint (minimum bound) on this Variable."),
00297              ArgDoc ("val", "Minimum value it can take")));
00298 
00299     declareMethod(
00300             rmm, "fprop", &Variable::fprop,
00301             (BodyDoc("Update value of this Var")));
00302 
00303 }
00304 
00306 // build_ //
00308 void Variable::build_()
00309 { 
00310     int l_previous = length();
00311     int w_previous = width();
00312     int l, w;
00313     recomputeSize(l, w);
00314     if(l==0 || w==0)
00315     {
00316         l = l_previous;
00317         w = w_previous;
00318     }
00319     // we call resize in all cases, even if we already had matValue correctly sized
00320     // the call to resize makes sure that value, valuedata, matGradient, gradient, gradientdata 
00321     // are correctly sized and initialized.
00322     resize(l, w);
00323 
00324     //if (l && w && (l != l_previous || w != w_previous))
00325     //    resize(l, w);
00326 }
00327 
00329 // build //
00331 void Variable::build()
00332 {
00333     inherited::build();
00334     build_();
00335 }
00336 
00337 
00339 // recomputeSize //
00341 void Variable::recomputeSize(int& l, int& w) const
00342 { l = length(); w = width(); }
00343 
00345 // resize //
00347 void Variable::resize(int l, int w)
00348 {
00349     value = Vec(); 
00350     // Force mod == width so that the call to 'toVec()' below does not crash.
00351     matValue.setMod(w);
00352     matValue.resize(l,w);
00353     value = matValue.toVec();
00354     if(value.getStorage())
00355         valuedata = value.data();
00356     else
00357         valuedata = 0;
00358 
00359     gradient = Vec();
00360     // Same as above.
00361     matGradient.setMod(w);
00362     matGradient.resize(l,w);
00363     gradient = matGradient.toVec();
00364     if (gradient.getStorage())
00365         gradientdata = gradient.data();
00366     else
00367         gradientdata = 0;
00368 }
00369 
00371 // sizeprop //
00373 void Variable::sizeprop()
00374 {
00375     int l,w;
00376     recomputeSize(l,w);
00377     resize(l,w);
00378 }
00379 
00381 // setParents //
00383 void Variable::setParents(const VarArray& parents)
00384 { PLERROR("In Variable::setParents  setParents() function not implemented for %s", classname().c_str()); }
00385 
00387 // defineValueLocation //
00389 Mat Variable::defineValueLocation(const Mat& m)
00390 {
00391     if(!m.isCompact())
00392         PLERROR("In Variable::defineValueLocation, Variables require compact"
00393                 " matrices");
00394     Mat oldm = matValue;
00395     matValue = m;
00396     value = matValue.toVec();
00397     if(value.getStorage())
00398         valuedata = value.data();
00399     else
00400         valuedata = 0;
00401     gradient = Vec(); // Temporarily frees a reference to gradient's storage.
00402     matGradient.setMod(matValue.width());
00403     matGradient.resize(matValue.length(), matValue.width());
00404     gradient = matGradient.toVec();
00405     if (gradient.getStorage())
00406         gradientdata = gradient.data();
00407     else
00408         gradientdata = 0;
00409     return oldm;
00410 }
00411 
00413 // defineGradientLocation //
00415 Mat Variable::defineGradientLocation(const Mat& m)
00416 {
00417     if(!m.isCompact())
00418         PLERROR("In Variable::defineGradientLocation, Variables require"
00419                 " compact matrices");
00420     Mat oldm = matGradient;
00421     matGradient = m;
00422     gradient  = matGradient.toVec();
00423     if (gradient.getStorage())
00424         gradientdata = gradient.data();
00425     else
00426         gradientdata = 0;
00427     value = Vec(); // Temporarily frees a reference to value's storage.
00428     matValue.setMod(matGradient.width());
00429     matValue.resize(matGradient.length(), matGradient.width());
00430     value = matValue.toVec();
00431     if(value.getStorage())
00432         valuedata = value.data();
00433     else
00434         valuedata = 0;
00435     return oldm;
00436 }
00437 
00438 /*
00439 void Variable::newwrite(PStream& out) const
00440 { 
00441     switch(out.outmode)
00442     {
00443     case PStream::raw_ascii:
00444     case PStream::pretty_ascii:
00445     {
00446         // This is just to strip "Variable" out of the class name (as they all
00447         // end in "Variable")
00448         string cn=info();
00449         string::size_type len = cn.length();
00450         if (len >= 9 && cn.substr(len-8,8) == "Variable")
00451             out << cn.substr(0,len-8) << endl;
00452         else
00453             out << cn << endl;
00454         break;
00455     }
00456     default:
00457         inherited::newwrite(out);
00458     }
00459 }
00460 */
00461 
00462 PLEARN_IMPLEMENT_ABSTRACT_OBJECT(Variable,
00463                                  "The base Variable class",
00464                                  ""
00465     );
00466 
00467 void Variable::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00468 {
00469     inherited::makeDeepCopyFromShallowCopy(copies);
00470     deepCopyField(value, copies);
00471     deepCopyField(gradient, copies);
00472     deepCopyField(matValue, copies);
00473     deepCopyField(matGradient, copies);
00474     if (value.getStorage())
00475         valuedata = value.data();
00476     else
00477         valuedata = 0;
00478     if (gradient.getStorage())
00479         gradientdata = gradient.data();
00480     else
00481         gradientdata = 0;
00482     varDeepCopyField(g, copies);
00483 }
00484 
00485 void Variable::clearDiagHessian() 
00486 { 
00487     if(!diaghessian) 
00488         resizeDiagHessian();
00489     diaghessian.clear();
00490 }
00491 
00492 
00493 void Variable::fbprop()
00494 {
00495     fprop();
00496     bprop();
00497 }
00498 
00499 void Variable::fbbprop()
00500 {
00501     fprop();
00502     bprop();
00503     bbprop();
00504 }
00505 
00506 void Variable::bbprop()
00507 { PLERROR("bbprop not implemented for this variable (%s)",classname().c_str()); }
00508 
00509 void Variable::symbolicBprop()
00510 { PLERROR("symbolicBprop not implemented for this variable (%s)",classname().c_str()); }
00511 
00512 void Variable::rfprop()
00513 { PLERROR("rfprop not implmented for this variable (%s)",classname().c_str()); }
00514 
00515 void Variable::setName(const string& the_name)
00516 { varname = the_name; }
00517 
00518 string Variable::getName() const
00519 {
00520     if (varname.size() == 0)
00521         return "#" + tostring(varnum);
00522 
00523     return varname;
00524 }
00525 
00526 void Variable::oldread(istream& in)
00527 { PLearn::read(in, value); }
00528 
00529 void Variable::write(ostream& out) const
00530 { PLearn::write(out, value); }
00531 
00532 
00533 Var Variable::subVec(int start, int len, bool transpose)
00534 {
00535     if(isColumnVec())
00536         return subMat(start,0,len,1,transpose);
00537     else if(isRowVec())
00538         return subMat(0,start,1,len,transpose);
00539 
00540     PLERROR("In Variable::subVec variable is not a vec (single column or single row)");
00541     return Var();
00542 }
00543 
00544 Var Variable::subMat(int i, int j, int sublength, int subwidth, bool do_transpose)
00545 { 
00546     if(do_transpose)
00547         return new SubMatTransposeVariable(this, i, j, sublength, subwidth); 
00548     else
00549         return new SubMatVariable(this, i, j, sublength, subwidth); 
00550 }
00551 
00552 void Variable::fprop_from_all_sources() 
00553 {
00554     VarArray all_sources = sources();
00555     unmarkAncestors();
00556     VarArray prop_path = propagationPath(all_sources,Var(this));
00557     prop_path.fprop();
00558 }
00559 
00560 void Variable::printInfos(bool print_gradient)
00561 {
00562     VarArray ancetres = ancestors();
00563     unmarkAncestors();
00564     ancetres.printInfo(print_gradient);
00565 }
00566 
00567 void Variable::accg(Var vg)
00568 {
00569     if(g || (vg.length()==length() && vg.width()==width()))
00570         g += vg;
00571     else // g does not exist
00572     {
00573         g = Var(length(),width());
00574         g += vg;
00575     }
00576 }
00577 
00578 void Variable::verifyGradient(real step) 
00579 { 
00580     VarArray inputs = sources();
00581     unmarkAncestors();
00582     Func f(inputs,Var(this));
00583     Vec p(inputs.nelems());
00584     inputs >> p;
00585     f->verifyGradient(p,step);
00586 }
00587 
00588 // set value = value + (step_size*coeff + b) * direction
00589 // with step_size possibly scaled down s.t. box constraints are satisfied
00590 // return true if box constraints have been hit with the update
00591 
00592 bool Variable::update(real step_size, Vec direction_vec, real coeff, real b)
00593 {
00594     bool hit = false;
00595     if(allows_partial_update)
00596         PLWARNING("Warning in Variable::update(real,Vec): will update every elements of the Variable");
00597     real full_coeff = step_size * coeff + b;
00598     if(min_value>-FLT_MAX || max_value<FLT_MAX)
00599         // constrained update
00600     {
00601         real* direction = direction_vec.data();
00602         for(int i=0; i<nelems(); i++)
00603         {
00604             valuedata[i] += (full_coeff) * direction[i];      
00605             if(valuedata[i]<min_value)
00606             {
00607                 valuedata[i]=min_value;
00608                 hit = true;
00609             }
00610             else if(valuedata[i]>max_value)
00611             {
00612                 valuedata[i]=max_value;
00613                 hit = true;
00614             }
00615         }
00616     }
00617     else
00618         // unconstrained update
00619     {
00620         real* direction = direction_vec.data();
00621         for(int i=0; i<nelems(); i++)
00622         {
00623             valuedata[i] += (full_coeff) * direction[i];      
00624         }
00625     }
00626     return hit;
00627 }
00628 
00629 bool Variable::update(Vec step_sizes, Vec direction_vec, real coeff, real b)
00630 {
00631     if(allows_partial_update)
00632         PLWARNING("Warning in Variable::update(Vec,Vec): will update every elements of the Variable");
00633     bool hit=false;
00634     real* direction = direction_vec.data();
00635     real* step = step_sizes.data();
00636     if(min_value>-FLT_MAX || max_value<FLT_MAX)
00637         // constrained update
00638     {
00639         for(int i=0; i<nelems(); i++)
00640         {
00641             valuedata[i] += (step[i] * coeff + b) * direction[i];
00642             if(valuedata[i]<min_value)
00643             {
00644                 valuedata[i]=min_value;
00645                 hit = true;
00646             }
00647             else if(valuedata[i]>max_value)
00648             {
00649                 valuedata[i]=max_value;
00650                 hit = true;
00651             }
00652         }
00653     }
00654     else
00655         // unconstrained update
00656         for(int i=0; i<nelems(); i++)
00657             valuedata[i] += (step[i] * coeff + b) * direction[i];
00658     return hit;
00659 }
00660 
00661 bool Variable::update(real step_size, bool clear)
00662 {
00663     bool hit=false;
00664     if(min_value>-FLT_MAX || max_value<FLT_MAX)
00665         // constrained update
00666     {
00667         if (allows_partial_update && gradient_status!=2)
00668         {
00669             if (gradient_status!=0)
00670             {
00671                 for (int r=0;r<rows_to_update.length();r++)
00672                 {
00673                     int row = rows_to_update[r];
00674                     real* direction = matGradient[row];
00675                     real* params = matValue[row];
00676                     for(int i=0; i<width(); i++)
00677                     {
00678                         params[i] += step_size*direction[i];      
00679                         if(params[i]<min_value)
00680                         {
00681                             params[i]=min_value;
00682                             hit = true;
00683                         }
00684                         else if(params[i]>max_value)
00685                         {
00686                             params[i]=max_value;
00687                             hit = true;
00688                         }
00689                         if (clear)
00690                             direction[i]=0;
00691                     }
00692                 }
00693                 if (clear) {
00694                     rows_to_update.resize(0);
00695                     gradient_status=0;
00696                 }
00697             }
00698         }
00699         else for (int row=0;row<length();row++)
00700         {
00701             real* direction = matGradient[row];
00702             real* params = matValue[row];
00703             for(int i=0; i<width(); i++)
00704             {
00705                 params[i] += step_size*direction[i];      
00706                 if(params[i]<min_value)
00707                 {
00708                     params[i]=min_value;
00709                     hit = true;
00710                 }
00711                 else if(params[i]>max_value)
00712                 {
00713                     params[i]=max_value;
00714                     hit = true;
00715                 }
00716                 if (clear)
00717                     direction[i]=0;
00718             }
00719         }
00720     }
00721     else
00722         // unconstrained update
00723     {
00724         if (allows_partial_update && gradient_status!=2)
00725         {
00726             if (gradient_status!=0)
00727             {
00728                 for (int r=0;r<rows_to_update.length();r++)
00729                 {
00730                     int row = rows_to_update[r];
00731                     real* direction = matGradient[row];
00732                     real* params = matValue[row];
00733                     for(int i=0; i<width(); i++)
00734                     {
00735                         params[i] += step_size*direction[i];      
00736                         if (clear)
00737                             direction[i] = 0;
00738                     }
00739                 }
00740                 if (clear) {
00741                     rows_to_update.resize(0);
00742                     gradient_status=0;
00743                 }
00744             }
00745         }
00746         else for (int row=0;row<length();row++)
00747         {
00748             real* direction = matGradient[row];
00749             real* params = matValue[row];      
00750             for(int i=0; i<width(); i++)
00751             {
00752                 params[i] += step_size*direction[i];      
00753                 if (clear)
00754                     direction[i] = 0;
00755             }
00756         }
00757     }
00758     return hit;
00759 }
00760 
00762 // updateWithWeightDecay //
00764 void Variable::updateWithWeightDecay(real step_size, real weight_decay, bool L1, bool clear)
00765 {
00766     // we do unconstrained update only here
00767     if (allows_partial_update && gradient_status!=2)
00768     {
00769         if (gradient_status!=0)
00770         {
00771             for (int r=0;r<rows_to_update.length();r++)
00772             {
00773                 int row = rows_to_update[r];
00774                 real* direction = matGradient[row];
00775                 real* params = matValue[row];
00776                 if (L1)
00777                 {
00778                     real delta = fabs(step_size)*weight_decay;
00779                     for(int i=0; i<width(); i++)
00780                     {
00781                         real pi = params[i];
00782                         params[i] += step_size*direction[i];
00783                         if (pi>delta)
00784                             params[i] -= delta;
00785                         else if (pi<-delta)
00786                             params[i] += delta;
00787                         else
00788                             params[i] = 0;
00789                         if (clear)
00790                             direction[i] = 0;
00791                     }
00792                 }
00793                 else // L2
00794                     for(int i=0; i<width(); i++)
00795                     {
00796                         params[i] += step_size*(direction[i] + weight_decay*params[i]);
00797                         if (clear)
00798                             direction[i] = 0;
00799                     }
00800             }
00801             if (clear) {
00802                 rows_to_update.resize(0);
00803                 gradient_status=0;
00804             }
00805         }
00806     }
00807     else
00808         for (int row=0;row<length();row++)
00809         {
00810             real* direction = matGradient[row];
00811             real* params = matValue[row];      
00812             if (L1)
00813             {
00814                 real delta = fabs(step_size)*weight_decay;
00815                 for(int i=0; i<width(); i++)
00816                 {
00817                     real pi = params[i];
00818                     params[i] += step_size*direction[i];
00819                     if (pi>delta)
00820                         params[i] -= delta;
00821                     else if (pi<-delta)
00822                         params[i] += delta;
00823                     if (clear)
00824                         direction[i] = 0;
00825                 }
00826             }
00827             else // L2
00828                 for(int i=0; i<width(); i++)
00829                 {
00830                     params[i] += step_size*(direction[i] + weight_decay*params[i]);
00831                     if (clear)
00832                         direction[i] = 0;
00833                 }
00834         }
00835 }
00836 
00837 
00839 // updateAndClear //
00841 void Variable::updateAndClear()
00842 {
00843     if (allows_partial_update && gradient_status!=2)
00844     {
00845         if (gradient_status!=0)
00846         {
00847             for (int r=0;r<rows_to_update.length();r++)
00848             {
00849                 int row = rows_to_update[r];
00850                 real* direction = matGradient[row];
00851                 real* params = matValue[row];
00852                 for(int i=0; i<width(); i++)
00853                 {
00854                     real& param_i = params[i];
00855                     param_i += direction[i];
00856                     if (param_i < min_value)
00857                         param_i = min_value;
00858                     else if (param_i > max_value)
00859                         param_i = max_value;
00860                     direction[i] = 0;
00861                 }              
00862             }
00863             rows_to_update.resize(0);
00864             gradient_status=0;
00865         }
00866     }
00867     else 
00868     {
00869         for(int i=0; i<nelems(); i++) {
00870             real& value = valuedata[i];
00871             value += gradientdata[i];
00872             if (value < min_value)
00873                 value = min_value;
00874             else if (value > max_value)
00875                 value = max_value;
00876         }
00877         gradient.clear();
00878     }
00879 }
00880 
00881 // set value = value + step_size * gradient
00882 // with step_size possibly scaled down s.t. box constraints are satisfied
00883 // return true if box constraints have been hit with the update
00884 
00885 /*
00886   bool Variable::update(real step_size)
00887   {
00888   bool hit=false;
00889   if(min_value>-FLT_MAX || max_value<FLT_MAX)
00890   // constrained update
00891   {
00892   real* direction = gradient.data();
00893   for(int i=0; i<nelems(); i++)
00894   {
00895   valuedata[i] += step_size*direction[i];      
00896   if(valuedata[i]<min_value)
00897   {
00898   valuedata[i]=min_value;
00899   hit = true;
00900   }
00901   else if(valuedata[i]>max_value)
00902   {
00903   valuedata[i]=max_value;
00904   hit = true;
00905   }
00906   }
00907   }
00908   else
00909   // unconstrained update
00910   {
00911   real* direction = gradient.data();
00912   for(int i=0; i<nelems(); i++)
00913   valuedata[i] += step_size*direction[i];      
00914   }
00915 
00916   return hit;
00917   }
00918 */
00919 
00920 
00921 // set value = new_value
00922 // projected down in each direction independently  in the
00923 // subspace in which the box constraints are satisfied.
00924 // return true if box constraints have been hit with the update
00925 bool Variable::update(Vec new_value)
00926 {
00927     if(allows_partial_update)
00928         PLWARNING("Warning in Variable::update(Vec): will update every elements of the Variable");
00929     bool hit=false;
00930     if(min_value>-FLT_MAX || max_value<FLT_MAX)
00931         // constrained update
00932     {
00933         real* new_v = new_value.data();
00934         for(int i=0; i<nelems(); i++)
00935         {
00936             valuedata[i] = new_v[i];      
00937             if(valuedata[i]<min_value)
00938             {
00939                 valuedata[i]=min_value;
00940                 hit = true;
00941             }
00942             else if(valuedata[i]>max_value)
00943             {
00944                 valuedata[i]=max_value;
00945                 hit = true;
00946             }
00947         }
00948     }
00949     else
00950         // unconstrained update
00951     {
00952         real* new_v = new_value.data();
00953         for(int i=0; i<nelems(); i++)
00954             valuedata[i] = new_v[i];      
00955     }
00956     return hit;
00957 }
00958 
00959 // Using the box constraints on the values, return
00960 // the maximum allowable step_size in the given direction
00961 // i.e., argmax_{step_size} {new = value + step_size * direction, new in box}
00962 real Variable::maxUpdate(Vec direction) 
00963 {
00964     real max_step_size=FLT_MAX;
00965     if(min_value>-FLT_MAX || max_value<FLT_MAX)
00966         // constrained update
00967     {
00968         real* dir = direction.data();
00969         for(int i=0; i<nelems(); i++)
00970         {
00971             real v = valuedata[i];
00972             if (v<min_value || v>max_value)
00973                 PLERROR("Variable::maxUpdate:current value %f already out of bounds (%f,%f)!",
00974                         v,min_value,max_value);
00975             if (dir[i]>0) // want to increase value: check max_value
00976             {
00977                 if (max_value<FLT_MAX) 
00978                 {
00979                     real maxstep = (max_value - v)/dir[i];
00980                     if (maxstep < max_step_size) max_step_size = maxstep;
00981                 }
00982             }
00983             else if (dir[i]<0) // want to decrease value: check min_value
00984             {
00985                 if (min_value > -FLT_MAX)
00986                 {
00987                     real maxstep = (min_value - v)/dir[i];
00988                     if (maxstep < max_step_size) max_step_size = maxstep;
00989                 }
00990             }
00991         }
00992     }
00993     // else unconstrained 
00994 
00995     return max_step_size;
00996 }
00997 
00998 void Variable::makeSharedValue(real* x, int n)
00999 {
01000     if (n!=nelems()) PLERROR("Variable::makeSharedValue, n(%d) inconsistent with nelems(%d)",
01001                              n,nelems());
01002     real* v=value.data();
01003     valuedata=x;
01004     if (x!=v)
01005         for (int j=0;j<n;j++)
01006             x[j]=v[j];
01007     value.storage = new Storage<real>(n,x);
01008     value.offset_ = 0;
01009     matValue.storage = value.storage;
01010     matValue.offset_ = 0;
01011     matValue.mod_ = matValue.width();
01012 }
01013 
01014 void Variable::makeSharedValue(PP<Storage<real> > storage, int offset_)
01015 {
01016     int n=nelems();
01017     if (storage->length()<offset_+n) 
01018         PLERROR("Variable::makeSharedValue, storage(%d) too small(%d+%d)",
01019                 storage->length(),offset_,nelems());
01020     real* v=value.data();
01021     real* x=valuedata=storage->data+offset_;
01022     if (x!=v)
01023         for (int j=0;j<n;j++)
01024             x[j]=v[j];
01025     value.storage = storage;
01026     value.offset_ = offset_;
01027     matValue.storage = storage;
01028     matValue.offset_ = offset_;
01029     matValue.mod_ = matValue.width();
01030 }
01031 
01032 void Variable::makeSharedGradient(Vec& v, int offset_)
01033 {
01034     makeSharedGradient(v.storage,v.offset_+offset_);
01035 }
01036 
01037 void Variable::makeSharedGradient(PP<Storage<real> > storage, int offset_)
01038 {
01039     int n=nelems();
01040     if (storage->length()<offset_+n) 
01041         PLERROR("Variable::makeSharedGradient, storage(%d) too small(%d+%d)",
01042                 storage->length(),offset_,nelems());
01043     real* v=gradient.data();
01044     real* x=gradientdata=storage->data+offset_;
01045     if (x!=v)
01046         for (int j=0;j<n;j++)
01047             x[j]=v[j];
01048     gradient.storage = storage;
01049     gradient.offset_ = offset_;
01050     matGradient.storage = storage;
01051     matGradient.offset_ = offset_;
01052     matGradient.mod_ = matGradient.width();
01053 }
01054 
01055   
01056 void Variable::makeSharedGradient(real* x, int n)
01057 {
01058     if (n!=nelems()) PLERROR("Variable::makeSharedGradient, n(%d) inconsistent with nelems(%d)",
01059                              n,nelems());
01060     real* v=gradient.data();
01061     gradientdata=x;
01062     if (x!=v)
01063         for (int j=0;j<n;j++)
01064             x[j]=v[j];
01065     gradient.storage = new Storage<real>(n,x);
01066     gradient.offset_ = 0;
01067     matGradient.storage = gradient.storage;
01068     matGradient.offset_ = 0;
01069     matGradient.mod_ = matGradient.width();
01070 }
01071 
01072 void Variable::makeSharedValue(Vec& v, int offset_)
01073 {
01074     makeSharedValue(v.storage,v.offset_+offset_);
01075 }
01076 
01077 void Variable::makeSharedRValue(PP<Storage<real> > storage, int offset_)
01078 {
01079     resizeRValue();
01080     int n=nelems();
01081     if (storage->length()<offset_+n) 
01082         PLERROR("Variable::makeSharedRValue, storage(%d) too small(%d+%d)",
01083                 storage->length(),offset_,nelems());
01084     real* v=rValue.data();
01085     real* x=rvaluedata=storage->data+offset_;
01086     if (x!=v)
01087         for (int j=0;j<n;j++)
01088             x[j]=v[j];
01089     rValue.storage = storage;
01090     rValue.offset_ = offset_;
01091     matRValue.storage = storage;
01092     matRValue.offset_ = offset_;
01093     matRValue.mod_ = matRValue.width();
01094 }
01095 
01096   
01097 void Variable::makeSharedRValue(real* x, int n)
01098 {
01099     if (n!=nelems()) PLERROR("Variable::makeSharedRValue, n(%d) inconsistent with nelems(%d)",
01100                              n,nelems());
01101     resizeRValue();
01102     real* v=rValue.data();
01103     rvaluedata=x;
01104     if (x!=v)
01105         for (int j=0;j<n;j++)
01106             x[j]=v[j];
01107     rValue.storage = new Storage<real>(n,x);
01108     rValue.offset_ = 0;
01109     matRValue.storage = rValue.storage;
01110     matRValue.offset_ = 0;
01111     matRValue.mod_ = matRValue.width();
01112 }
01113 
01115 // makeSharedRValue //
01117 void Variable::makeSharedRValue(Vec& v, int offset_)
01118 {
01119     makeSharedRValue(v.storage,v.offset_+offset_);
01120 }
01121     
01123 // resizeDiagHessian //
01125 void Variable::resizeDiagHessian()
01126 {
01127     matDiagHessian.resize(length(),width());
01128     diaghessian = matDiagHessian.toVec();
01129     diaghessiandata = diaghessian.data();
01130 }
01131 
01133 // resizeRValue //
01135 void Variable::resizeRValue()
01136 {
01137     if (!rvaluedata)
01138     {
01139         matRValue.resize(length(),width());
01140         rValue = matRValue.toVec();
01141         rvaluedata = rValue.data();
01142     }
01143 }
01144 
01146 // setValueSubMat //
01148 void Variable::setValueSubMat(const Mat& submat, int istart, int jstart)
01149 {
01150     matValue.subMat(istart, jstart, submat.length(), submat.width()) << submat;
01151 }
01152 
01153 
01154 } // end of namespace PLearn
01155 
01156 
01157 /*
01158   Local Variables:
01159   mode:c++
01160   c-basic-offset:4
01161   c-file-style:"stroustrup"
01162   c-file-offsets:((innamespace . 0)(inline-open . 0))
01163   indent-tabs-mode:nil
01164   fill-column:79
01165   End:
01166 */
01167 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines