DecisionTree.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2014, Institute for Artificial Intelligence,
00005  *  Universität Bremen.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Institute for Artificial Intelligence,
00019  *     Universität Bremen, nor the names of its contributors may be
00020  *     used to endorse or promote products derived from this software
00021  *     without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *********************************************************************/
00036 
00040 #include <plugins/prediction/DecisionTree.h>
00041 
00042 
00043 namespace beliefstate {
00044   DecisionTree::DecisionTree() {
00045     this->init();
00046   }
00047   
00048   DecisionTree::DecisionTree(std::string strFile) {
00049     this->init("", strFile);
00050   }
00051   
00052   DecisionTree::~DecisionTree() {
00053     if(m_jsnDecisionTree) {
00054       delete m_jsnDecisionTree;
00055     }
00056   }
00057   
00058   void DecisionTree::init(std::string strMessagePrefix, std::string strFile) {
00059     if(strMessagePrefix == "") {
00060       strMessagePrefix = "dtree-aux";
00061     }
00062     
00063     this->setMessagePrefixLabel(strMessagePrefix);
00064     
00065     m_jsnDecisionTree = new JSON();
00066   }
00067   
00068   bool DecisionTree::load(std::string strFile) {
00069     bool bReturn = false;
00070     
00071     if(strFile != "") {
00072       std::ifstream ifFile(strFile.c_str());
00073       
00074       if(ifFile.good()) {
00075         std::string strJSON((istreambuf_iterator<char>(ifFile)),
00076                             (istreambuf_iterator<char>()));
00077         
00078         m_jsnDecisionTree->parse(strJSON);
00079         
00080         if(m_jsnDecisionTree->rootProperty()) {
00081           bReturn = true;
00082         }
00083       }
00084     }
00085     
00086     return bReturn;
00087   }
00088   
00089   Property* DecisionTree::evaluate(CKeyValuePair* ckvpFeatures) {
00090     Property* prReturn = NULL;
00091     
00092     if(m_jsnDecisionTree) {
00093       if(m_jsnDecisionTree->rootProperty()) {
00094         prReturn = this->evaluate(m_jsnDecisionTree->rootProperty(), ckvpFeatures);
00095       }
00096     }
00097     
00098     return prReturn;
00099   }
00100   
00101   bool DecisionTree::relationSatisfied(Property* prRelation, CKeyValuePair* ckvpFeatures) {
00102     // This is a relation, evaluate it
00103     bool bResult = false;
00104     Property* prOperator = NULL;
00105     Property* prVariable = NULL;
00106     Property* prValue = NULL;
00107     
00108     std::string strOperator = prRelation->key();
00109     prVariable = prRelation->namedSubProperty("variable");
00110     prValue = prRelation->namedSubProperty("value");
00111 
00112     if(strOperator != "" && prVariable && prValue) {
00113       if(ckvpFeatures->childForKey(prVariable->getString())) {
00114         if(strOperator == "=") { // Operator: "="
00115           switch(prValue->type()) {
00116           case Property::String: {
00117             std::string strFeature = ckvpFeatures->stringValue(prVariable->getString());
00118             bResult = (strFeature == prValue->getString());
00119           } break;
00120             
00121           case Property::Integer: {
00122             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00123             bResult = (nFeature == prValue->getInteger());
00124           } break;
00125             
00126           case Property::Double: {
00127             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00128             bResult = (fFeature == (float)prValue->getDouble());
00129           } break;
00130             
00131           case Property::Boolean: {
00132             bool bFeature = (ckvpFeatures->floatValue(prVariable->getString()) != 0.0);
00133             bResult = (bFeature == prValue->getBoolean());
00134           } break;
00135             
00136           default: {
00137             this->warn("Unknown property value type, not evaluating.");
00138           } break;
00139           }
00140         } else if(strOperator == "<") { // Operator: "<"
00141           switch(prValue->type()) {
00142           case Property::Integer: {
00143             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00144             bResult = (nFeature < prValue->getInteger());
00145           } break;
00146             
00147           case Property::Double: {
00148             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00149             bResult = (fFeature < (float)prValue->getDouble());
00150           } break;
00151             
00152           default: {
00153             this->warn("Unknown property value type, not evaluating.");
00154           } break;
00155           }
00156         } else if(strOperator == "<=") { // Operator: "<="
00157           switch(prValue->type()) {
00158           case Property::Integer: {
00159             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00160             bResult = (nFeature <= prValue->getInteger());
00161           } break;
00162           
00163           case Property::Double: {
00164             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00165             bResult = (fFeature <= (float)prValue->getDouble());
00166           } break;
00167           
00168           default: {
00169             this->warn("Unknown property value type, not evaluating.");
00170           } break;
00171           }
00172         } else if(strOperator == ">") { // Operator: ">"
00173           switch(prValue->type()) {
00174           case Property::Integer: {
00175             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00176             bResult = (nFeature > prValue->getInteger());
00177           } break;
00178           
00179           case Property::Double: {
00180             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00181             bResult = (fFeature > (float)prValue->getDouble());
00182           } break;
00183           
00184           default: {
00185             this->warn("Unknown property value type, not evaluating.");
00186           } break;
00187           }
00188         } else if(strOperator == ">=") { // Operator: ">="
00189           switch(prValue->type()) {
00190           case Property::Integer: {
00191             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00192             bResult = (nFeature >= prValue->getInteger());
00193           } break;
00194           
00195           case Property::Double: {
00196             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00197             bResult = (fFeature >= (float)prValue->getDouble());
00198           } break;
00199           
00200           default: {
00201             this->warn("Unknown property value type, not evaluating.");
00202           } break;
00203           }
00204         } else if(strOperator == "!=") { // Operator: "!="
00205           switch(prValue->type()) {
00206           case Property::String: {
00207             std::string strFeature = ckvpFeatures->stringValue(prVariable->getString());
00208             bResult = (strFeature != prValue->getString());
00209           } break;
00210           
00211           case Property::Integer: {
00212             int nFeature = (int)ckvpFeatures->floatValue(prVariable->getString());
00213             bResult = (nFeature != prValue->getInteger());
00214           } break;
00215           
00216           case Property::Double: {
00217             float fFeature = ckvpFeatures->floatValue(prVariable->getString());
00218             bResult = (fFeature != (float)prValue->getDouble());
00219           } break;
00220           
00221           case Property::Boolean: {
00222             bool bFeature = (ckvpFeatures->floatValue(prVariable->getString()) != 0.0);
00223             bResult = (bFeature != prValue->getBoolean());
00224           } break;
00225           
00226           default: {
00227             this->warn("Unknown property value type, not evaluating.");
00228           } break;
00229         }
00230         } else {
00231           this->warn("Unknown operator: '" + strOperator + "'");
00232         }
00233       } else {
00234         this->missingFeature(strOperator, prVariable->getString());
00235       }
00236     } else {
00237       this->warn("Missing operator, variable, or value.");
00238     }
00239     
00240     return bResult;
00241   }
00242   
00243   Property* DecisionTree::evaluate(Property* prTree, CKeyValuePair* ckvpFeatures) {
00244     Property* prResult = NULL;
00245     
00246     if(prTree && ckvpFeatures) {
00247       Property* prAction = prTree->namedSubProperty("relation");
00248       
00249       if(prAction) {
00250         bool bResult = this->relationSatisfied(prAction->subProperties().front(), ckvpFeatures);
00251         
00252         prResult = prTree->namedSubProperty((bResult ? "true" : "false"));
00253         if(prResult) {
00254           list<Property*> lstSubActions = prResult->subProperties();
00255             
00256           for(Property* prSubAction : lstSubActions) {
00257             prResult = this->evaluate(prSubAction, ckvpFeatures);
00258               
00259             if(prResult) {
00260               break;
00261             }
00262           }
00263         }
00264       } else if((prAction = prTree->namedSubProperty("result")) != NULL) {
00265         // This is a leaf (i.e. result), return it
00266         prResult = prAction;
00267       } else if(prTree->type() == Property::Array) {
00268         for(Property* prSubAction : prTree->subProperties()) {
00269           prResult = this->evaluate(prSubAction, ckvpFeatures);
00270             
00271           if(prResult) {
00272             break;
00273           }
00274         }
00275       } else {
00276         // This is something unknown, report it
00277         this->warn("Cannot evaluate decision tree branch:");
00278         prTree->print();
00279       }
00280     }
00281       
00282     return prResult;
00283   }
00284   
00285   std::vector<CKeyValuePair*> DecisionTree::invert(Property* prTargetResult, CKeyValuePair* ckvpFeatures) {
00286     std::vector<CKeyValuePair*> vecSolutions;
00287     
00288     // First, find all branches with the target result.
00289     std::vector<Property*> vecSolutionsTemp = this->findBranchesWithResult(prTargetResult);
00290     std::vector< std::vector<Property*> > vecSolutionsStraightened = this->straightenResultBranches(vecSolutionsTemp);
00291     for(Property* prSolution : vecSolutionsTemp) {
00292       delete prSolution;
00293     }
00294     
00295     // Second, filter out any relations that are already satisfied via
00296     // ckvpFeatures.
00297     std::vector< std::vector<Property*> > vecSols;
00298     
00299     for(std::vector<Property*> vecSolution : vecSolutionsStraightened) {
00300       std::vector<Property*> vecSolutionNew;
00301       
00302       for(std::vector<Property*>::iterator itSolutionStep = vecSolution.begin();
00303           itSolutionStep != vecSolution.end();
00304           ++itSolutionStep) {
00305         if(!this->relationSatisfied(*itSolutionStep, ckvpFeatures)) {
00306           vecSolutionNew.push_back(*itSolutionStep);
00307         } else {
00308           delete *itSolutionStep;
00309         }
00310       }
00311       
00312       vecSols.push_back(vecSolutionNew);
00313     }
00314     
00315     for(std::vector<Property*> vecSolution : vecSols) {
00316       if(vecSolution.size() > 0) {
00317         CKeyValuePair* ckvpSolution = new CKeyValuePair("solution", LIST);
00318       
00319         for(Property* prSolutionStep : vecSolution) {
00320           CKeyValuePair* ckvpStep = new CKeyValuePair("step", LIST);
00321           ckvpSolution->addChild(ckvpStep);
00322         
00323           ckvpStep->setValue("relation", prSolutionStep->key());
00324         
00325           std::list<std::string> lstCopyFields;
00326           lstCopyFields.push_back("variable");
00327           lstCopyFields.push_back("value");
00328         
00329           for(std::string strFieldName : lstCopyFields) {
00330             Property* prField = prSolutionStep->namedSubProperty(strFieldName);
00331           
00332             switch(prField->type()) {
00333             case Property::String:
00334               ckvpStep->setValue(strFieldName, prField->getString());
00335               break;
00336 
00337             case Property::Integer:
00338               ckvpStep->setValue(strFieldName, prField->getInteger());
00339               break;
00340 
00341             case Property::Double:
00342               ckvpStep->setValue(strFieldName, prField->getDouble());
00343               break;
00344 
00345             case Property::Boolean:
00346               ckvpStep->setValue(strFieldName, prField->getBoolean());
00347               break;
00348             
00349             default:
00350               this->warn("Unknown property type.");
00351               break;
00352             }
00353           }
00354         
00355           delete prSolutionStep;
00356         }
00357       
00358         vecSolutions.push_back(ckvpSolution);
00359       }
00360     }
00361     
00362     return vecSolutions;
00363   }
00364   
00365   std::vector< std::vector<Property*> > DecisionTree::straightenResultBranches(std::vector<Property*> vecSolutionBranches) {
00366     std::vector< std::vector<Property*> > vecSolutionsStraightened;
00367     
00368     for(Property* prSolutionBranch : vecSolutionBranches) {
00369       vecSolutionsStraightened.push_back(this->straightenResultBranch(prSolutionBranch));
00370     }
00371     
00372     return vecSolutionsStraightened;
00373   }
00374   
00375   std::vector<Property*> DecisionTree::straightenResultBranch(Property* prSolutionBranch) {
00376     std::vector<Property*> vecStraightened;
00377     
00378     // We're only interested in relations, as we already know the
00379     // target result.
00380     if(prSolutionBranch->key() == "relation") {
00381       if(prSolutionBranch->subProperties().size() == 1) {
00382         vecStraightened.push_back(new Property(prSolutionBranch->subProperties().front())); // Copy
00383       }
00384     }
00385     
00386     for(Property* prSub : prSolutionBranch->subProperties()) {
00387       std::vector<Property*> vecSubStraightened = this->straightenResultBranch(prSub);
00388       
00389       for(Property* prSubStraightened : vecSubStraightened) {
00390         vecStraightened.push_back(new Property(prSubStraightened));
00391         delete prSubStraightened; // Got copied
00392       }
00393     }
00394     
00395     return vecStraightened;
00396   }
00397   
00398   std::vector<Property*> DecisionTree::findBranchesWithResult(Property* prTargetResult, Property* prStart) {
00399     std::vector<Property*> vecSolutions;
00400     
00401     if(!prStart) {
00402       prStart = m_jsnDecisionTree->rootProperty();
00403     }
00404     
00405     Property* prResult = prStart->namedSubProperty("result");
00406     if(prResult) {
00407       // This is the result leaf, we're at our destination. Check its
00408       // value vs. prTargetResult.
00409       
00410       // TODO(winkler): Extend so that not only string results can be
00411       // used (i.e. check for the type of both `Property's and compare
00412       // them accordingly.
00413       if(prResult->getString() == prTargetResult->getString()) {
00414         // Yes, this is indeed the result we're looking for. Add a
00415         // copy to the solutions and terminate.
00416         vecSolutions.push_back(new Property(prStart));
00417       } else {
00418         // No, this was not the result we were looking for. Silently
00419         // terminate and return nothing.
00420       }
00421     } else {
00422       // This is not a leaf node. We need to recurse from here, and
00423       // interprete the returned results appropriately.
00424       
00425       // Preserve for later.
00426       Property* prRelation = prStart->namedSubProperty("relation");
00427       
00428       // Try all branches except `relation', as that is (similar to
00429       // `result') reserved.
00430       for(Property* prBranch : prStart->subProperties()) {
00431         if(prBranch->key() != "relation") {
00432           // Yes, this is a trieable branch.
00433           std::vector<Property*> vecSubSolutions = this->findBranchesWithResult(prTargetResult, prBranch);
00434           
00435           // Process them here.
00436           for(Property* prSubSolution : vecSubSolutions) {
00437             Property* prSolutionBranch = new Property("", Property::Object);
00438             
00439             if(prRelation) {
00440               prSolutionBranch->addSubProperty(new Property(prRelation));
00441             }
00442             
00443             prSolutionBranch->addSubProperty(new Property(prSubSolution));
00444             delete prSubSolution; // Not used anymore, got deep-copied
00445             
00446             vecSolutions.push_back(prSolutionBranch);
00447           }
00448         }
00449       }
00450     }
00451     
00452     return vecSolutions;
00453   }
00454   
00455   void DecisionTree::missingFeature(std::string strOperator, std::string strFeatureName) {
00456     this->warn("Decision Tree: '" + strFeatureName + "' missing from feature space while evaluating operator '" + strOperator + "'.");
00457   }
00458   
00459   void DecisionTree::missingOperand(std::string strOperator) {
00460     this->warn("Decision Tree: Operand missing while evaluating operator '" + strOperator + "'.");
00461   }
00462 }


beliefstate
Author(s): Jan Winkler
autogenerated on Sun Oct 5 2014 22:30:15