Marsyas
0.6.0-alpha
|
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 }