PluginPrediction.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/PluginPrediction.h>
00041 
00042 
00043 namespace beliefstate {
00044   namespace plugins {
00045     PLUGIN_CLASS::PLUGIN_CLASS() {
00046       m_jsnModel = NULL;
00047       m_dtDecisionTree = NULL;
00048       m_expOwl = NULL;
00049       m_bInsidePredictionModel = false;
00050       m_ndActive = NULL;
00051       m_bModelLoaded = false;
00052       m_nClassFlexibility = 6;
00053       
00054       this->setPluginVersion("0.1");
00055     }
00056 
00057     PLUGIN_CLASS::~PLUGIN_CLASS() {
00058       if(m_jsnModel) {
00059         delete m_jsnModel;
00060       }
00061 
00062       if(m_dtDecisionTree) {
00063         delete m_dtDecisionTree;
00064       }
00065       
00066       if(m_expOwl) {
00067         delete m_expOwl;
00068       }
00069       
00070       m_lstPredictionStack.clear();
00071     }
00072     
00073     Result PLUGIN_CLASS::init(int argc, char** argv) {
00074       Result resInit = defaultResult();
00075       
00076       // Plan node control events
00077       this->setSubscribedToEvent("symbolic-begin-context", true);
00078       this->setSubscribedToEvent("symbolic-end-context", true);
00079       this->setSubscribedToEvent("symbolic-node-active", true);
00080       
00081       this->setOffersService("predict", true);
00082       this->setOffersService("load-model", true);
00083       this->setOffersService("invert-decision-tree", true);
00084       
00085       // Prepare the JSON prediction model parsers
00086       m_jsnModel = new JSON();
00087       m_dtDecisionTree = new DecisionTree();
00088       
00089       // OWL Exporter instance for class ontology
00090       m_expOwl = new CExporterOwl();
00091       
00092       return resInit;
00093     }
00094     
00095     Result PLUGIN_CLASS::deinit() {
00096       return defaultResult();
00097     }
00098     
00099     Result PLUGIN_CLASS::cycle() {
00100       Result resCycle = defaultResult();
00101       this->deployCycleData(resCycle);
00102       
00103       return resCycle;
00104     }
00105     
00106     Event PLUGIN_CLASS::consumeServiceEvent(ServiceEvent seEvent) {
00107       Event evReturn = this->Plugin::consumeServiceEvent(seEvent);
00108       
00109       if(seEvent.siServiceIdentifier == SI_REQUEST) {
00110         if(seEvent.strServiceName == "predict") {
00111           ServiceEvent seResponse = eventInResponseTo(seEvent);
00112           CDesignator* cdRequest = seEvent.cdDesignator;
00113           
00114           seResponse.bPreserve = true;
00115           CDesignator* cdResponse = new CDesignator();
00116           cdResponse->setType(ACTION);
00117           
00118           bool bSuccess = false;
00119           if(m_bModelLoaded) {
00120             this->info("Received Prediction Request.");
00121             
00122             if(!this->predict(cdRequest, cdResponse)) {
00123               this->fail("Failed to predict!");
00124               
00125               cdResponse->setValue("success", false);
00126               cdResponse->setValue("message", "Failed to predict.");
00127             } else {
00128               cdResponse->setValue("success", true);
00129             }
00130           } else {
00131             this->warn("Received Prediction Request without loaded prediction model. Ignoring.");
00132             
00133             cdResponse->setValue("success", false);
00134             cdResponse->setValue("message", "No model loaded.");
00135           }
00136           
00137           seResponse.cdDesignator = cdResponse;
00138           this->deployServiceEvent(seResponse);
00139         } else if(seEvent.strServiceName == "load-model") {
00140           CDesignator* cdRequest = seEvent.cdDesignator;
00141           
00142           if(cdRequest) {
00143             if(cdRequest->stringValue("type") == "task-tree") {
00144               std::string strPath = cdRequest->stringValue("file");
00145               
00146               if(strPath != "") {
00147                 this->info("Load task tree model: '" + strPath + "'");
00148                 
00149                 if(this->load(strPath)) {
00150                   this->info("Finished loading task tree model.");
00151                   m_bModelLoaded = true;
00152                 } else {
00153                   this->fail("Failed to load task tree model.");
00154                 }
00155               } else {
00156                 this->fail("No file specified for loading task tree model.");
00157               }
00158             } else if(cdRequest->stringValue("type") == "decision-tree") {
00159               std::string strPath = cdRequest->stringValue("file");
00160               this->info("Load decision tree model: '" + strPath + "'");
00161               
00162               if(strPath != "") {
00163                 if(this->loadDecisionTree(strPath)) {
00164                   this->info("Finished loading decision tree model.");
00165                 } else {
00166                   this->fail("Failed to load decision tree model.");
00167                 }
00168               } else {
00169                 this->fail("No file specified for loading decision tree model.");
00170               }
00171             }
00172           }
00173           
00174           ServiceEvent seResponse = eventInResponseTo(seEvent);
00175           this->deployServiceEvent(seResponse);
00176         } else if(seEvent.strServiceName == "invert-decision-tree") {
00177           if(seEvent.cdDesignator) {
00178             std::string strTargetResult = seEvent.cdDesignator->stringValue("target-result");
00179             
00180             if(strTargetResult != "") {
00181               CKeyValuePair* ckvpFeatures = seEvent.cdDesignator->childForKey("features");
00182               
00183               Property* prTargetResult = new Property();
00184               prTargetResult->set(strTargetResult);
00185               
00186               vector<CKeyValuePair*> vecSolutions = m_dtDecisionTree->invert(prTargetResult, ckvpFeatures);
00187               delete prTargetResult;
00188               
00189               ServiceEvent seResponse = eventInResponseTo(seEvent);
00190               seResponse.bPreserve = true;
00191               seResponse.cdDesignator = new CDesignator();
00192               seResponse.cdDesignator->setType(ACTION);
00193               
00194               CKeyValuePair* ckvpSolutions = seResponse.cdDesignator->addChild("solutions");
00195               
00196               for(int nI = 0; nI < vecSolutions.size(); nI++) {
00197                 CKeyValuePair* ckvpSolution = vecSolutions.at(nI);
00198                 
00199                 ckvpSolution->setKey("solution_" + this->str(nI));
00200                 ckvpSolutions->addChild(ckvpSolution);
00201               }
00202               
00203               this->deployServiceEvent(seResponse);
00204             } else {
00205               this->warn("Cannot invert decision tree model without target result.");
00206             }
00207           }
00208         }
00209       }
00210       
00211       return evReturn;
00212     }
00213     
00214     void PLUGIN_CLASS::consumeEvent(Event evEvent) {
00215       if(evEvent.strEventName == "symbolic-begin-context") {
00216         if(m_bInsidePredictionModel) {
00217           if(evEvent.lstNodes.size() > 0) {
00218             this->descend(evEvent.lstNodes.front());
00219             issueGlobalToken("symbolic-context-began");
00220           } else {
00221             this->warn("Consuming 'symbolic-begin-context' event without nodes!");
00222           }
00223         } else {
00224           this->fail("No prediction model loaded, won't descend.");
00225         }
00226       } else if(evEvent.strEventName == "symbolic-end-context") {
00227         if(evEvent.lstNodes.size() > 0) {
00228           this->ascend(evEvent.lstNodes.front());
00229         } else {
00230           this->warn("Consuming 'symbolic-end-context' event without nodes!");
00231         }
00232       } else if(evEvent.strEventName == "symbolic-node-active") {
00233         if(evEvent.lstNodes.size() > 0) {
00234           Node* ndNode = evEvent.lstNodes.front();
00235           
00236           this->info("Prediction context is now node '" + ndNode->title() + "'.");//, of class '" + m_expOwl->owlClassForNode(ndNode, true) + "'.");
00237           m_ndActive = ndNode;
00238         } else {
00239           this->info("Prediction context is now top-level (so not predicting).");
00240           m_ndActive = NULL;
00241         }
00242       }
00243     }
00244     
00245     bool PLUGIN_CLASS::serviceCallbackLoad(designator_integration_msgs::DesignatorCommunication::Request &req, designator_integration_msgs::DesignatorCommunication::Response &res) {
00246       bool bSuccess = false;
00247       
00248       CDesignator* desigRequest = new CDesignator(req.request.designator);
00249       CDesignator* desigResponse = new CDesignator();
00250       desigResponse->setType(ACTION);
00251       
00252       if(desigRequest->stringValue("load") == "model") {
00253         this->info("Received Model Load Request.");
00254         
00255         std::string strFile = desigRequest->stringValue("file");
00256         if(strFile != "") {
00257           this->info(" - Load model: '" + strFile + "'");
00258           
00259           bSuccess = this->load(strFile);
00260           
00261           if(bSuccess) {
00262             m_bModelLoaded = true;
00263           }
00264         } else {
00265           this->fail(" - No model file specified!");
00266         }
00267       }
00268       
00269       res.response.designators.push_back(desigResponse->serializeToMessage());
00270       
00271       delete desigRequest;
00272       delete desigResponse;
00273       
00274       return bSuccess;
00275     }
00276     
00277     bool PLUGIN_CLASS::load(string strFile) {
00278       bool bReturn = false;
00279       
00280       std::ifstream ifFile(strFile.c_str());
00281       if(ifFile.good()) {
00282         std::string strJSON((istreambuf_iterator<char>(ifFile)), (istreambuf_iterator<char>()));
00283         
00284         m_jsnModel->parse(strJSON);
00285         
00286         if(m_jsnModel->rootProperty()) {
00287           this->info("Successfully loaded and parsed model '" + strFile + "'.");
00288           bReturn = true;
00289           m_bInsidePredictionModel = true;
00290           
00291           this->info("Okay, descending to 'Toplevel'.");
00292           this->descend("Toplevel");
00293           
00294           bReturn = true;
00295         } else {
00296           this->fail("Failed to load model '" + strFile + "', unable to parse.");
00297         }
00298       } else {
00299         this->fail("Failed to load model '" + strFile + "', file does not exist.");
00300         bReturn = false;
00301       }
00302       
00303       ifFile.close();
00304       
00305       return bReturn;
00306     }
00307     
00308     bool PLUGIN_CLASS::descend(Node* ndDescend) {
00309       return this->descend(ndDescend->title());
00310       //return this->descend(m_expOwl->owlClassForNode(ndDescend, true));
00311     }
00312     
00313     bool PLUGIN_CLASS::descend(std::string strClass, bool bForceClass) {
00314       bool bResult = false;
00315       bool bFlexible = false;
00316       
00317       m_mtxStackProtect.lock();
00318       Property* prDescendTo = NULL;
00319       
00320       if(m_lstPredictionStack.size() == 0) {
00321         // We are on top-level and must look for the class to ascend
00322         // into in the current JSON model keys.
00323         prDescendTo = m_jsnModel->rootProperty()->namedSubProperty(strClass);
00324       } else {
00325         // We are already somewhere in the prediction tree and must
00326         // find a fitting subType in the currently active state.
00327         if(m_bInsidePredictionModel) {
00328           Property* prActive = m_lstPredictionStack.back().prLevel;
00329           
00330           if(prActive->namedSubProperty("subTypes")) {
00331             prDescendTo = prActive->namedSubProperty("subTypes")->namedSubProperty(strClass);
00332           }
00333           
00334           if(!prDescendTo) {
00335             // There was no subType to descend to. Check if we are
00336             // still flexible for other types. If that is the case,
00337             // use the first type that comes up.
00338             std::string strClasses = "";
00339             for(Property* prType : prActive->namedSubProperty("subTypes")->subProperties()) {
00340               if(strClasses != "") {
00341                 strClasses += " ";
00342               }
00343               
00344               strClasses += prType->key();
00345             }
00346             
00347             this->warn("No match for descend. Available classes: " + strClasses);
00348             
00349             if(m_nClassFlexibility > 0) {
00350               // Yes, we are flexible. Check if there is at least one subType.
00351               if(prActive->namedSubProperty("subTypes")->subProperties().size() > 0) {
00352                 // There are subTypes. Use the first one.
00353                 this->warn("Being flexible: Accept '" + prActive->namedSubProperty("subTypes")->subProperties().front()->key() + "' for '" + strClass + "'");
00354                 prDescendTo = prActive->namedSubProperty("subTypes")->subProperties().front();
00355                 bFlexible = true;
00356                 m_nClassFlexibility--;
00357               }
00358             }
00359           }
00360         }
00361       }
00362       
00363       if(prDescendTo) {
00364         m_bInsidePredictionModel = true;
00365         
00366         this->info("Descending by class: '" + strClass + "'");
00367         
00368         PredictionTrack ptTrack;
00369         ptTrack.prLevel = prDescendTo;
00370         ptTrack.strClass = (bFlexible ? "*" : strClass);
00371         m_lstPredictionStack.push_back(ptTrack);
00372         
00373         bResult = true;
00374       } else {
00375         this->warn("Couldn't descend by class: '" + strClass + "'");
00376         
00377         if(m_bInsidePredictionModel) {
00378           this->warn("Leaving prediction model, entering unknown sub-tree.");
00379           m_bInsidePredictionModel = false;
00380         } else {
00381           this->info("Continuing descent into unknown sub-tree.");
00382         }
00383         
00384         PredictionTrack ptTrack;
00385         ptTrack.prLevel = NULL;
00386         ptTrack.strClass = strClass;
00387         m_lstPredictionStack.push_back(ptTrack);
00388       }
00389       
00390       m_mtxStackProtect.unlock();
00391       
00392       return bResult;
00393     }
00394     
00395     bool PLUGIN_CLASS::ascend(Node* ndAscend) {
00396       bool bResult = false;
00397       
00398       std::string strClass = ndAscend->title();//m_expOwl->owlClassForNode(ndAscend, true);
00399       
00400       m_mtxStackProtect.lock();
00401       if(m_lstPredictionStack.size() > 0) {
00402         bool bGoon = true;
00403         
00404         while(bGoon) {
00405           PredictionTrack ptTrack = m_lstPredictionStack.back();
00406           m_lstPredictionStack.pop_back();
00407           
00408           if(strClass == ptTrack.strClass || ptTrack.strClass == "*") {
00409             if(ptTrack.strClass == "*") {
00410               m_nClassFlexibility++;
00411             }
00412             
00413             if(m_lstPredictionStack.size() > 0) {
00414               PredictionTrack ptTrackNew = m_lstPredictionStack.back();
00415             
00416               if(m_bInsidePredictionModel) {
00417                 this->info("Ascending by class: '" + strClass + "'");
00418               } else {
00419                 if(ptTrackNew.prLevel) {
00420                   this->info("Ascending back into prediction model. Predictions possible again.");
00421                   m_bInsidePredictionModel = true;
00422                 } else {
00423                   this->info("Ascending out of part of the unknown sub-tree.");
00424                 }
00425               }
00426             } else {
00427               this->fail("Careful: Ascending into empty prediction stack. This shouldn't happen, as at least a 'Toplevel' stack entry is expected.");
00428             }
00429             
00430             bResult = true;
00431           } else {
00432             this->fail("Tried to ascend from '" + strClass + "', but we're in '" + ptTrack.strClass + "'. Moving up the chain.");
00433             bResult = true;
00434           }
00435           
00436           if(m_lstPredictionStack.size() == 0 || bResult) {
00437             bGoon = false;
00438           }
00439         }
00440       } else {
00441         this->warn("Ascending although we have no prediction tree loaded. Did you load a model? (Hint: The answer is 'No'.)");
00442       }
00443       
00444       m_mtxStackProtect.unlock();
00445       
00446       return bResult;
00447     }
00448     
00449     PLUGIN_CLASS::PredictionResult PLUGIN_CLASS::evaluatePredictionRequest(Property* prActive, CKeyValuePair* ckvpFeatures, CKeyValuePair* ckvpRequested) {
00450       PredictionResult presResult;
00451       
00452       // Here, the actual prediction takes place.
00453       std::map<std::string, double> mapEffectiveFailureRates;
00454       
00455       // Automatic tree walking
00456       std::list< pair<Property*, int> > lstLinearTree = this->linearizeTree(prActive, m_lstPredictionStack.size());
00457       std::list< pair<Property*, int> > lstRunTree;
00458       double dLeftOverSuccess = 1.0f;
00459       
00460       for(pair<Property*, int> prCurrent : lstLinearTree) {
00461         lstRunTree.push_back(prCurrent);
00462         
00463         presResult = this->probability(lstRunTree, ckvpFeatures, ckvpRequested);
00464         
00465         for(pair<std::string, double> prFailure : presResult.mapFailureProbabilities) {
00466           if(mapEffectiveFailureRates.find(prFailure.first) == mapEffectiveFailureRates.end()) {
00467             mapEffectiveFailureRates[prFailure.first] = 0.0f;
00468           }
00469           
00470           mapEffectiveFailureRates[prFailure.first] += (prFailure.second * dLeftOverSuccess);
00471           dLeftOverSuccess -= (prFailure.second * dLeftOverSuccess);
00472         }
00473       }
00474       
00475       presResult.dSuccessRate = 1.0f;
00476       
00477       for(std::pair<std::string, double> prFailure : mapEffectiveFailureRates) {
00478         presResult.mapFailureProbabilities[prFailure.first] = prFailure.second;
00479         presResult.dSuccessRate -= prFailure.second;
00480       }
00481       
00482       return presResult;
00483     }
00484     
00485     bool PLUGIN_CLASS::predict(CDesignator* cdRequest, CDesignator* cdResponse) {
00486       bool bResult = false;
00487       
00488       m_mtxStackProtect.lock();
00489       
00490       if(m_bInsidePredictionModel) {
00491         // Make sure there is a model present before diving into the
00492         // tree.
00493         if(m_jsnModel->rootProperty()) {
00494           // Make sure we are actually in a valid prediction state.
00495           if(m_lstPredictionStack.size() > 0) {
00496             PredictionTrack ptCurrent = m_lstPredictionStack.back();
00497             this->info("Predicting for class: '" + ptCurrent.strClass + "' at level " + this->str((int)m_lstPredictionStack.size()));
00498             
00499             CKeyValuePair* ckvpActiveFeatures = cdRequest->childForKey("active-features");
00500             CKeyValuePair* ckvpRequestedFeatures = cdRequest->childForKey("requested-features");
00501             
00502             if(ckvpActiveFeatures) {
00503               std::string strActiveFeatures = "";
00504               
00505               for(std::string strKey : ckvpActiveFeatures->keys()) {
00506                 if(strActiveFeatures != "") {
00507                   strActiveFeatures += ", ";
00508                 }
00509                 
00510                 strActiveFeatures += strKey;
00511               }
00512               
00513               this->info("Active features: " + strActiveFeatures);
00514             }
00515             
00516             if(ckvpRequestedFeatures) {
00517               std::string strRequestedFeatures = "";
00518               
00519               for(std::string strKey : ckvpRequestedFeatures->keys()) {
00520                 if(strRequestedFeatures != "") {
00521                   strRequestedFeatures += ", ";
00522                 }
00523                 
00524                 strRequestedFeatures += strKey;
00525               }
00526               
00527               this->info("Requested features: " + strRequestedFeatures);
00528             }
00529             
00530             // Here, the actual prediction is triggered.
00531             Property* prActive = m_lstPredictionStack.back().prLevel;
00532             PredictionResult presResult = this->evaluatePredictionRequest(prActive, ckvpActiveFeatures, ckvpRequestedFeatures);
00533             
00534             // Prepare the results for returning them.
00535             // Failure probabilities
00536             CKeyValuePair* ckvpFailureProbabilities = cdResponse->addChild("failures");
00537             for(pair<std::string, double> prFailure : presResult.mapFailureProbabilities) {
00538               ckvpFailureProbabilities->setValue(prFailure.first, prFailure.second);
00539             }
00540             
00541             // Requested feature values
00542             CKeyValuePair* ckvpRequestedFeatureValues = cdResponse->addChild("requested");
00543             for(pair<std::string, Property*> prReq : presResult.mapRequestedFeatureValues) {
00544               ckvpRequestedFeatureValues->addChild(prReq.first, prReq.second);
00545             }
00546             
00547             // Overall success rate
00548             cdResponse->setValue("success", presResult.dSuccessRate);
00549             
00550             bResult = true;
00551           } else {
00552             this->fail("Nothing on the prediction stack. Toplevel not loaded. This is bad.");
00553           }
00554         } else {
00555           this->fail("No root element loaded. Did you load a prediction model?");
00556         }
00557       } else {
00558         this->fail("Outside of prediction model, no predictions possible.");
00559       }
00560       
00561       m_mtxStackProtect.unlock();
00562       
00563       return bResult;
00564     }
00565     
00566     std::list< pair<Property*, int> > PLUGIN_CLASS::linearizeTree(Property* prTop, int nLevel) {
00567       std::list< pair<Property*, int> > lstProps;
00568       lstProps.push_back(make_pair(prTop, nLevel));
00569       
00570       Property* prSubs = prTop->namedSubProperty("subTypes");
00571       
00572       if(prSubs) {
00573         for(Property* prSub : prSubs->subProperties()) {
00574           std::list< pair<Property*, int> > lstSubProps = this->linearizeTree(prSub, nLevel + 1);
00575           
00576           for(pair<Property*, int> prSubSub : lstSubProps) {
00577             lstProps.push_back(make_pair(prSubSub.first, prSubSub.second));
00578           }
00579         }
00580       }
00581       
00582       return lstProps;
00583     }
00584     
00585     std::map<std::string, double> PLUGIN_CLASS::relativeFailureOccurrences(std::list<Property*> lstFailures, int nTracks) {
00586       std::map<std::string, int> mapFailureOcc;
00587       
00588       for(Property* prFailure : lstFailures) {
00589         std::string strType = prFailure->namedSubProperty("type")->getString();
00590         
00591         if(mapFailureOcc[strType] == 0) {
00592           mapFailureOcc[strType] = 1;
00593         } else {
00594           mapFailureOcc[strType]++;
00595         }
00596       }
00597       
00598       std::map<std::string, double> mapFailureRelOcc;
00599       for(std::pair<std::string, int> prFailOcc : mapFailureOcc) {
00600         mapFailureRelOcc[prFailOcc.first] = (double)prFailOcc.second / (double)nTracks;
00601       }
00602       
00603       return mapFailureRelOcc;
00604     }
00605     
00606     std::list<Property*> PLUGIN_CLASS::failuresForTreeNode(Property* prNode) {
00607       if(m_mapNodeFailures.find(prNode) != m_mapNodeFailures.end()) {
00608         return m_mapNodeFailures[prNode];
00609       }
00610       
00611       std::list<Property*> lstEmpty;
00612       return lstEmpty;
00613     }
00614     
00615     std::list<Property*> PLUGIN_CLASS::parametersForTreeNode(Property* prNode) {
00616       if(m_mapNodeParameters.find(prNode) != m_mapNodeParameters.end()) {
00617         return m_mapNodeParameters[prNode];
00618       }
00619       
00620       std::list<Property*> lstEmpty;
00621       return lstEmpty;
00622     }
00623     
00624     std::map<std::string, double> PLUGIN_CLASS::relativeFailuresForNode(Property* prNode, int nLevel, CKeyValuePair* ckvpFeatures) {
00625       std::map<std::string, double> mapRelFail;
00626       
00627       if(prNode) {
00628         ckvpFeatures->setValue("Level", nLevel);
00629         ckvpFeatures->setValue("Task", prNode->key());
00630         
00631         // Find TAGNAME if this is a tag
00632         std::string strTagName = "";
00633         
00634         CKeyValuePair* ckvpDesignators = m_ndActive->metaInformation()->childForKey("designators");
00635         if(ckvpDesignators) {
00636           for(CKeyValuePair* ckvpDesignator : ckvpDesignators->children()) {
00637             CKeyValuePair* ckvpDescription = ckvpDesignator->childForKey("description");
00638             
00639             if(ckvpDescription) {
00640               strTagName = ckvpDescription->stringValue("tagname");
00641               
00642               if(strTagName != "") {
00643                 break;
00644               }
00645             }
00646           }
00647         }
00648         
00649         if(strTagName != "") {
00650           ckvpFeatures->setValue("TAGNAME", strTagName);
00651         }
00652         
00653         Property* prResult = this->evaluateDecisionTree(ckvpFeatures);
00654         
00655         if(prResult) {
00656           // TODO(winkler): The confidence in the calculated failure
00657           // is not always 1.0f (although mostly it is very close to
00658           // it). This information is coming from Weka as well and
00659           // should be contained in the decision tree model.
00660           mapRelFail[prResult->getString()] = 1.0f;
00661         }
00662       }
00663       
00664       return mapRelFail;
00665     }
00666     
00667     PLUGIN_CLASS::PredictionResult PLUGIN_CLASS::probability(std::list< pair<Property*, int> > lstSequence, CKeyValuePair* ckvpFeatures, CKeyValuePair* ckvpRequested) {
00668       PredictionResult presResult;
00669       
00670       // TODO(winkler): Right now, the requested features
00671       // `ckvpRequested' are not evaluated. Implement this.
00672       
00673       if(lstSequence.size() > 0) {
00674         Property* prCurrentNode = lstSequence.back().first;
00675         
00676         // Relative occurrences
00677         std::map<std::string, double> mapFailureRelOcc = this->relativeFailuresForNode(prCurrentNode, lstSequence.back().second, ckvpFeatures);
00678         
00679         double dLocalSuccess = 1.0f;
00680         for(std::pair<std::string, double> prPair : mapFailureRelOcc) {
00681           dLocalSuccess -= prPair.second;
00682         }
00683         
00684         std::map<std::string, double> mapSubFailures;
00685         if(dLocalSuccess > 0.0f) { // Recursion only makes sense if we can actually reach the sub-node.
00686           // Prepare list for recursion
00687           std::list< pair<Property*, int> > lstAllButLast = lstSequence;
00688           lstAllButLast.pop_back();
00689           
00690           // Recurse
00691           PredictionResult presSub = this->probability(lstAllButLast, ckvpFeatures, ckvpRequested);
00692           mapSubFailures = presSub.mapFailureProbabilities;
00693         } else {
00694           lstSequence.clear();
00695         }
00696         
00697         // Add the failures from THIS node
00698         for(std::pair<std::string, double> prMap : mapFailureRelOcc) {
00699           presResult.mapFailureProbabilities[prMap.first] = prMap.second;
00700         }
00701         
00702         double dLocalSuccessDelta = 0.0f;
00703         
00704         // Add the failures from CHILD node
00705         for(pair<std::string, double> prFailure : mapSubFailures) {
00706           presResult.mapFailureProbabilities[prFailure.first] = prFailure.second * dLocalSuccess;
00707           dLocalSuccessDelta += presResult.mapFailureProbabilities[prFailure.first];
00708         }
00709         
00710         presResult.dSuccessRate = dLocalSuccess - dLocalSuccessDelta;
00711       } else {
00712         // This is the node we already passed. This is S0, which has
00713         // 100% success rate per definition.
00714         presResult.dSuccessRate = 1.0f;
00715       }
00716       
00717       return presResult;
00718     }
00719     
00720     bool PLUGIN_CLASS::loadDecisionTree(std::string strPath) {
00721       return m_dtDecisionTree->load(strPath);
00722     }
00723     
00724     Property* PLUGIN_CLASS::evaluateDecisionTree(CKeyValuePair* ckvpFeatures) {
00725       return m_dtDecisionTree->evaluate(ckvpFeatures);
00726     }
00727   }
00728   
00729   extern "C" plugins::PLUGIN_CLASS* createInstance() {
00730     return new plugins::PLUGIN_CLASS();
00731   }
00732   
00733   extern "C" void destroyInstance(plugins::PLUGIN_CLASS* icDestroy) {
00734     delete icDestroy;
00735   }
00736 }


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