Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/SelfSimilarityMatrix.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2006 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "SelfSimilarityMatrix.h"
00020 
00021 using namespace std;
00022 using namespace Marsyas;
00023 
00024 SelfSimilarityMatrix::SelfSimilarityMatrix(mrs_string name):MarSystem("SelfSimilarityMatrix", name)
00025 {
00026   isComposite_ = true;
00027   addControls();
00028 }
00029 
00030 SelfSimilarityMatrix::SelfSimilarityMatrix(const SelfSimilarityMatrix& a) : MarSystem(a)
00031 {
00032   ctrl_covMatrix_ = getctrl("mrs_realvec/covMatrix");
00033   ctrl_calcCovMatrix_ = getctrl("mrs_natural/calcCovMatrix");
00034   ctrl_normalize_ = getctrl("mrs_string/normalize");
00035   ctrl_stdDev_ = getctrl("mrs_real/stdDev");
00036 
00037   ctrl_mode_ = getctrl("mrs_natural/mode");
00038   ctrl_instanceIndexes_ = getctrl("mrs_realvec/instanceIndexes");
00039   ctrl_nInstances_ = getctrl("mrs_natural/nInstances");
00040   ctrl_done_ = getctrl("mrs_bool/done");
00041 }
00042 
00043 SelfSimilarityMatrix::~SelfSimilarityMatrix()
00044 {
00045 }
00046 
00047 MarSystem*
00048 SelfSimilarityMatrix::clone() const
00049 {
00050   return new SelfSimilarityMatrix(*this);
00051 }
00052 
00053 void
00054 SelfSimilarityMatrix::addControls()
00055 {
00056   addControl("mrs_realvec/covMatrix", realvec(), ctrl_covMatrix_);
00057   addControl("mrs_natural/calcCovMatrix", SelfSimilarityMatrix::noCovMatrix, ctrl_calcCovMatrix_);
00058   addControl("mrs_string/normalize", "none", ctrl_normalize_);
00059   addControl("mrs_real/stdDev", 1.0, ctrl_stdDev_);
00060 
00061   addControl("mrs_natural/mode", SelfSimilarityMatrix::outputDistanceMatrix, ctrl_mode_);
00062   ctrl_mode_->setState(true);
00063   addControl("mrs_realvec/instanceIndexes", realvec(), ctrl_instanceIndexes_);
00064   addControl("mrs_natural/nInstances", -1, ctrl_nInstances_);
00065   addControl("mrs_bool/done", false, ctrl_done_);
00066 }
00067 
00068 void
00069 SelfSimilarityMatrix::myUpdate(MarControlPtr sender)
00070 {
00071   (void) sender;  //suppress warning of unused parameter(s)
00072 
00073   if(this->getctrl("mrs_natural/mode")->to<mrs_natural>() ==  SelfSimilarityMatrix::outputDistanceMatrix)
00074   {
00075     // The output similarity matrix is a squared matrix with
00076     // dimension equal to the number of elements (i.e. samples)
00077     // in the input
00078 
00079     //forward flow propagation
00080     ctrl_onObservations_->setValue(ctrl_inSamples_, NOUPDATE);
00081     ctrl_onSamples_->setValue(ctrl_inSamples_, NOUPDATE);
00082     ctrl_osrate_->setValue(ctrl_osrate_, NOUPDATE); //[?]
00083     ostringstream oss;
00084     for(mrs_natural o=0; o < ctrl_onObservations_->to<mrs_natural>(); ++o)
00085       oss << "SelfSimilarityMatrix_" << o << ",";
00086     ctrl_onObsNames_->setValue(oss.str(), NOUPDATE);
00087 
00088     //if the metric MarSystem exists and at least there is an element
00089     // to process at the input (it may not exist!), configure child marSystem.
00090     // Otherwise do nothing to it.
00091     child_count_t child_count = marsystems_.size();
00092     if(child_count == 1 && inSamples_ > 0)
00093     {
00094       //allocate realvec for the pair of stacked feature vectors
00095       //to be used in the similarity computation
00096       i_featVec_.create(ctrl_inObservations_->to<mrs_natural>());
00097       j_featVec_.create(ctrl_inObservations_->to<mrs_natural>());
00098       stackedFeatVecs_.create(ctrl_inObservations_->to<mrs_natural>()*2, 1);
00099 
00100       //configure the metric child MarSystem:
00101       //the input to metric are the two vector to process stacked vertically
00102       marsystems_[0]->setctrl("mrs_natural/inObservations", ctrl_inObservations_->to<mrs_natural>()*2);
00103       marsystems_[0]->setctrl("mrs_natural/inSamples", 1);
00104       marsystems_[0]->setctrl("mrs_real/israte", ctrl_israte_->to<mrs_real>()); //[?]
00105       oss.clear();
00106       oss << ctrl_inObsNames_->to<mrs_string>() << ctrl_inObsNames_->to<mrs_string>(); //[?]
00107       marsystems_[0]->setctrl("mrs_string/inObsNames", oss.str());
00108       marsystems_[0]->update();
00109 
00110       //link covMatrix control
00111       MarControlPtr ctrl_childCovMat = marsystems_[0]->getctrl("mrs_realvec/covMatrix");
00112       if(!ctrl_childCovMat.isInvalid())
00113         ctrl_childCovMat->linkTo(ctrl_covMatrix_);
00114 
00115       //allocate space for the metric result (must be a real value)
00116       metricResult_.create(1,1);
00117 
00118       //check if the child is a valid metric MarSystem
00119       if(marsystems_[0]->getctrl("mrs_natural/onObservations") != 1 ||
00120           marsystems_[0]->getctrl("mrs_natural/onSamples") != 1)
00121       {
00122         MRSWARN("SelfSimilarityMatrix::myUpdate - invalid Child Metric MarSystem (does not output a real value)!");
00123       }
00124     }
00125     else if(child_count > 1)
00126     {
00127       MRSWARN("similarityMatrix::myUpdate - more than one children MarSystem exists! Only one MarSystem should be added as a metric!");
00128     }
00129   }
00130   else if(this->getctrl("mrs_natural/mode")->to<mrs_natural>() ==  SelfSimilarityMatrix::outputPairDistance)
00131   {
00132     // The output similarity matrix is a single value with
00133     // the distance between the two instances (column vectors) at the input
00134 
00135     //forward flow propagation
00136     ctrl_onObservations_->setValue(1, NOUPDATE);
00137     ctrl_onSamples_->setValue(1, NOUPDATE);
00138     ctrl_osrate_->setValue(ctrl_osrate_, NOUPDATE); //???:
00139     ostringstream oss;
00140     oss << "Distance";
00141     ctrl_onObsNames_->setValue("Distance", NOUPDATE);
00142 
00143     //if the metric MarSystem exists and at least there is an element
00144     // to process at the input (it may not exist!), configure child marSystem.
00145     // Otherwise do nothing to it.
00146     child_count_t child_count = marsystems_.size();
00147     if(child_count == 1 && inSamples_ > 0)
00148     {
00149       //allocate realvec for the pair of stacked feature vectors
00150       //to be used in the similarity computation
00151       i_featVec_.create(ctrl_inObservations_->to<mrs_natural>());
00152       j_featVec_.create(ctrl_inObservations_->to<mrs_natural>());
00153       stackedFeatVecs_.create(ctrl_inObservations_->to<mrs_natural>()*2, 1);
00154 
00155       //configure the metric child MarSystem:
00156       //the input to metric are the two vector to process stacked vertically
00157       marsystems_[0]->setctrl("mrs_natural/inObservations", ctrl_inObservations_->to<mrs_natural>()*2);
00158       marsystems_[0]->setctrl("mrs_natural/inSamples", 1);
00159       marsystems_[0]->setctrl("mrs_real/israte", ctrl_israte_->to<mrs_real>()); //???:
00160       oss.clear();
00161       oss << ctrl_inObsNames_->to<mrs_string>() << ctrl_inObsNames_->to<mrs_string>(); //???:
00162       marsystems_[0]->setctrl("mrs_string/inObsNames", oss.str());
00163       marsystems_[0]->update();
00164 
00165       //link covMatrix control
00166       MarControlPtr ctrl_childCovMat = marsystems_[0]->getctrl("mrs_realvec/covMatrix");
00167       if(!ctrl_childCovMat.isInvalid())
00168         ctrl_childCovMat->linkTo(ctrl_covMatrix_);
00169 
00170       //allocate space for the metric result (must be a real value)
00171       metricResult_.create(1,1);
00172 
00173       MarControlAccessor acc(ctrl_instanceIndexes_);
00174       realvec& instIdxs = acc.to<mrs_realvec>();
00175       instIdxs.create(0.0, 1, 2); //init row vector
00176 
00177       ctrl_done_->setValue(false, NOUPDATE);
00178 
00179       //check if the child is a valid metric MarSystem
00180       if(marsystems_[0]->getctrl("mrs_natural/onObservations") != 1 ||
00181           marsystems_[0]->getctrl("mrs_natural/onSamples") != 1)
00182       {
00183         MRSWARN("SelfSimilarityMatrix::myUpdate - invalid Child Metric MarSystem (does not output a real value)!");
00184       }
00185     }
00186     else if(child_count > 1)
00187     {
00188       MRSWARN("similarityMatrix::myUpdate - more than one children MarSystem exists! Only one MarSystem should be added as a metric!");
00189     }
00190   }
00191 
00192 }
00193 
00194 void
00195 SelfSimilarityMatrix::myProcess(realvec& in, realvec& out)
00196 {
00197   if(this->getctrl("mrs_natural/mode")->to<mrs_natural>() ==  SelfSimilarityMatrix::outputDistanceMatrix)
00198   {
00199     //check if there are any elements to process at the input
00200     //(in some cases, they may not exist!) - otherwise, do nothing
00201     //(i.e. output will be zeroed out)
00202     if(inSamples_ > 0)
00203     {
00204       child_count_t child_count = marsystems_.size();
00205       if(child_count == 1)
00206       {
00207         mrs_natural nfeats = in.getRows();
00208 
00209         //normalize input features if necessary
00210         if(ctrl_normalize_->to<mrs_string>() == "MinMax")
00211           in.normObsMinMax(); // (x - min)/(max - min)
00212         else if(ctrl_normalize_->to<mrs_string>() == "MeanStd")
00213           in.normObs(); // (x - mean)/std
00214 
00215         //calculate the Covariance Matrix from the input, if defined
00216         if(ctrl_calcCovMatrix_->to<mrs_natural>() & SelfSimilarityMatrix::fixedStdDev)
00217         {
00218           //fill covMatrix diagonal with fixed value (remaining values are zero)
00219           MarControlAccessor acc(ctrl_covMatrix_);
00220           realvec& covMatrix = acc.to<mrs_realvec>();
00221           covMatrix.create(inObservations_, inObservations_);
00222           mrs_real var = ctrl_stdDev_->to<mrs_real>();
00223           var *= var;
00224           for(mrs_natural i=0; i< inObservations_; ++i)
00225           {
00226             covMatrix(i,i) = var;
00227           }
00228         }
00229         else if(ctrl_calcCovMatrix_->to<mrs_natural>() & SelfSimilarityMatrix::diagCovMatrix)
00230         {
00231           in.varObs(vars_); //FASTER -> only get the vars for each feature
00232           mrs_natural dim = vars_.getSize();
00233           //fill covMatrix diagonal with var values (remaining values are zero)
00234           MarControlAccessor acc(ctrl_covMatrix_);
00235           realvec& covMatrix = acc.to<mrs_realvec>();
00236           covMatrix.create(dim, dim);
00237           for(mrs_natural i=0; i< dim; ++i)
00238           {
00239             covMatrix(i,i) = vars_(i);
00240           }
00241         }
00242         else if(ctrl_calcCovMatrix_->to<mrs_natural>() & SelfSimilarityMatrix::fullCovMatrix)
00243         {
00244           MarControlAccessor acc(ctrl_covMatrix_);
00245           realvec& covMatrix = acc.to<mrs_realvec>();
00246           in.covariance(covMatrix); //SLOWER -> estimate the full cov matrix
00247         }
00248         else if(ctrl_calcCovMatrix_->to<mrs_natural>() == SelfSimilarityMatrix::noCovMatrix)
00249         {
00250           ctrl_covMatrix_->setValue(realvec());
00251         }
00252 
00253         for(mrs_natural i=0; i < in.getCols(); ++i)
00254         {
00255           in.getCol(i, i_featVec_);
00256           for(mrs_natural j=0; j <= i; ++j)
00257           {
00258             in.getCol(j, j_featVec_);
00259 
00260             //stack i and j feat vecs
00261             for(mrs_natural r=0; r < nfeats; ++r)
00262             {
00263               stackedFeatVecs_(r, 0) = i_featVec_(r);
00264               stackedFeatVecs_(r+nfeats, 0) = j_featVec_(r);
00265             }
00266             //do the metric calculation for these two feat vectors
00267             //and store it in the similarity matrix (which is symmetric)
00268             marsystems_[0]->process(stackedFeatVecs_, metricResult_);
00269             out(i,j) = metricResult_(0,0);
00270             //metric should be symmetric!
00271             out(j, i) = out(i, j);
00272           }
00273         }
00274       }
00275       else
00276       {
00277         out.setval(0.0);
00278         if(child_count == 0)
00279         {
00280           MRSWARN("SelfSimilarityMatrix::myProcess - no Child Metric MarSystem added - outputting zero similarity matrix!");
00281         }
00282         else
00283         {
00284           MRSWARN("SelfSimilarityMatrix::myProcess - more than one Child MarSystem exists (i.e. invalid metric) - outputting zero similarity matrix!");
00285         }
00286       }
00287     }
00288 
00289     //MATLAB_PUT(out, "simMatrix");
00290     //MATLAB_EVAL("figure(1);imagesc(simMatrix);");
00291 
00292     //MATLAB_PUT(out, "simMat");
00293     //MATLAB_EVAL(name_+"=["+name_+",simMat(:)'];");
00294   }
00295   else if(this->getctrl("mrs_natural/mode")->to<mrs_natural>() ==  SelfSimilarityMatrix::outputPairDistance)
00296   {
00297     if(inSamples_ == 2) //we always need two column vector instances at input
00298     {
00299       child_count_t child_count = marsystems_.size();
00300       if(child_count == 1)
00301       {
00302         MarControlAccessor acc(ctrl_instanceIndexes_);
00303         realvec& instIdxs = acc.to<mrs_realvec>();
00304         mrs_natural i = mrs_natural(instIdxs(0));
00305         mrs_natural j = mrs_natural(instIdxs(1));
00306 
00307         //check for out of bound indexes (which could have been set
00308         //by someone outside changing the value of the ctrl_instanceIndexes control)
00309         mrs_natural nInstances = ctrl_nInstances_->to<mrs_natural>();
00310         if(i >= nInstances || j >= nInstances)
00311           ctrl_done_->setValue(true);
00312 
00313 
00314         if(!ctrl_done_->isTrue())
00315         {
00316           mrs_natural nfeats = in.getRows();
00317 
00318           //COMPUTE DISTANCE between the two column vector at input
00319           in.getCol(0, i_featVec_);
00320           in.getCol(1, j_featVec_);
00321 
00322           //stack i and j feat vecs
00323           for(mrs_natural r=0; r < nfeats; ++r)
00324           {
00325             stackedFeatVecs_(r, 0) = i_featVec_(r);
00326             stackedFeatVecs_(r+nfeats, 0) = j_featVec_(r);
00327           }
00328 
00329           //do the metric calculation for these two feat vectors
00330           //and send it to the output
00331           marsystems_[0]->process(stackedFeatVecs_, out);
00332           //out(0) = metricResult_(0,0);
00333         }
00334         else
00335         {
00336           //Self Similarity has completed all pair-wise similarity computations
00337           //so, it will just send zero valued values and a warning
00338           out(0) = 0.0;
00339           MRSWARN("SelfSimilarityMatrix::myProcess - no more pairwise similarity computations to be performed - outputting zero similarity value!")
00340         }
00341 
00342         //Select indexes for next pair of instances for distance computation
00343         //Similarity matrix is tringular simetric, so we should just compute
00344         //half of it (including diagonal). These indexes are to be used by some
00345         //source MarSystem that has a control linked to ctrl_instanceIndexes (e.g. WekaSource)
00346         if (i < j)
00347           ++i;
00348         else
00349         {
00350           ++j;
00351           i = 0;
00352         }
00353         if (j >= nInstances)
00354         {
00355           ctrl_done_->setValue(true);
00356           j = -1; //used to signal that there are no more instance pairs to compute
00357           i = -1; //used to signal that there are no more instance pairs to compute
00358         }
00359         else
00360           ctrl_done_->setValue(false);
00361 
00362         //set indexes into the ctrl_instanceIndexes_ control
00363         instIdxs(0) = i;
00364         instIdxs(1) = j;
00365       }
00366       else
00367       {
00368         out.setval(0.0);
00369         if(child_count == 0)
00370         {
00371           MRSWARN("SelfSimilarityMatrix::myProcess - no Child Metric MarSystem added - outputting zero similarity value!");
00372         }
00373         else
00374         {
00375           MRSWARN("SelfSimilarityMatrix::myProcess - more than one Child MarSystem exists (i.e. invalid metric) - outputting zero similarity value!");
00376         }
00377       }
00378     }
00379   }
00380 }