From d32b4738551b7d8fbfe0657cf8cf16ee022aa807 Mon Sep 17 00:00:00 2001
From: Franck Dary <franck.dary@etu.univ-amu.fr>
Date: Mon, 3 Dec 2018 13:55:38 +0100
Subject: [PATCH] Added error detector decoder

---
 error_correction/CMakeLists.txt               |   5 +
 .../src/macaon_decode_error_detector.cpp      | 160 ++++++++++++++++++
 .../src/macaon_train_error_detector.cpp       |  38 ++++-
 3 files changed, 194 insertions(+), 9 deletions(-)
 create mode 100644 error_correction/src/macaon_decode_error_detector.cpp

diff --git a/error_correction/CMakeLists.txt b/error_correction/CMakeLists.txt
index e5db282..6cfa2b5 100644
--- a/error_correction/CMakeLists.txt
+++ b/error_correction/CMakeLists.txt
@@ -9,3 +9,8 @@ add_executable(macaon_train_error_detector src/macaon_train_error_detector.cpp)
 target_link_libraries(macaon_train_error_detector transition_machine)
 target_link_libraries(macaon_train_error_detector ${Boost_PROGRAM_OPTIONS_LIBRARY})
 install(TARGETS macaon_train_error_detector DESTINATION bin)
+
+add_executable(macaon_decode_error_detector src/macaon_decode_error_detector.cpp)
+target_link_libraries(macaon_decode_error_detector transition_machine)
+target_link_libraries(macaon_decode_error_detector ${Boost_PROGRAM_OPTIONS_LIBRARY})
+install(TARGETS macaon_decode_error_detector DESTINATION bin)
diff --git a/error_correction/src/macaon_decode_error_detector.cpp b/error_correction/src/macaon_decode_error_detector.cpp
new file mode 100644
index 0000000..488fabf
--- /dev/null
+++ b/error_correction/src/macaon_decode_error_detector.cpp
@@ -0,0 +1,160 @@
+/// @file macaon_decode_error_detector.cpp
+/// @author Franck Dary
+/// @version 1.0
+/// @date 2018-12-03
+
+#include <cstdio>
+#include <cstdlib>
+#include <boost/program_options.hpp>
+#include "BD.hpp"
+#include "Config.hpp"
+#include "TransitionMachine.hpp"
+
+namespace po = boost::program_options;
+
+/// @brief Get the list of mandatory and optional program arguments.
+///
+/// @return The lists.
+po::options_description getOptionsDescription()
+{
+  po::options_description desc("Command-Line Arguments ");
+
+  po::options_description req("Required");
+  req.add_options()
+    ("expName", po::value<std::string>()->required(),
+      "Name of this experiment")
+    ("tm", po::value<std::string>()->required(),
+      "File describing the Tape Machine to use")
+    ("bd", po::value<std::string>()->required(),
+      "BD file that describes the multi-tapes buffer")
+    ("mcd", po::value<std::string>()->required(),
+      "MCD file that describes the input")
+    ("input,I", po::value<std::string>()->required(),
+      "Input file formated according to the mcd");
+
+  po::options_description opt("Optional");
+  opt.add_options()
+    ("help,h", "Produce this help message")
+    ("debug,d", "Print infos on stderr")
+    ("printEntropy", "Print entropy for each sequence")
+    ("sequenceDelimiterTape", po::value<std::string>()->default_value("EOS"),
+      "The name of the buffer's tape that contains the delimiter token for a sequence")
+    ("sequenceDelimiter", po::value<std::string>()->default_value("1"),
+      "The value of the token that act as a delimiter for sequences")
+    ("showFeatureRepresentation", po::value<bool>()->default_value(false),
+      "For each state of the Config, show its feature representation")
+    ("lang", po::value<std::string>()->default_value("fr"),
+      "Language you are working with");
+
+  desc.add(req).add(opt);
+
+  return desc;
+}
+
+/// @brief Store the program arguments inside a variables_map
+///
+/// @param od The description of all the possible options.
+/// @param argc The number of arguments given to this program.
+/// @param argv The values of arguments given to this program.
+///
+/// @return The variables map
+po::variables_map checkOptions(po::options_description & od, int argc, char ** argv)
+{
+  po::variables_map vm;
+
+  try {po::store(po::parse_command_line(argc, argv, od), vm);}
+  catch(std::exception& e)
+  {
+    std::cerr << "Error: " << e.what() << "\n";
+    od.print(std::cerr);
+    exit(1);
+  }
+
+  if (vm.count("help"))
+  {
+    std::cout << od << "\n";
+    exit(0);
+  }
+
+  try {po::notify(vm);}
+  catch(std::exception& e)
+  {
+    std::cerr << "Error: " << e.what() << "\n";
+    od.print(std::cerr);
+    exit(1);
+  }
+
+  return vm;
+}
+
+/// @brief Uses a pre-trained TransitionMachine to predict and add information to a structured input file.
+///
+/// @param argc The number of arguments given to this program.
+/// @param argv[] Array of arguments given to this program.
+///
+/// @return 0 if there was no crash.
+int main(int argc, char * argv[])
+{
+  auto od = getOptionsDescription();
+
+  po::variables_map vm = checkOptions(od, argc, argv);
+
+  ProgramParameters::expName = vm["expName"].as<std::string>();
+  ProgramParameters::tmName = vm["tm"].as<std::string>();
+  ProgramParameters::bdName = vm["bd"].as<std::string>();
+  ProgramParameters::input = vm["input"].as<std::string>();
+  ProgramParameters::mcdName = vm["mcd"].as<std::string>();
+  ProgramParameters::debug = vm.count("debug") == 0 ? false : true;
+  ProgramParameters::printEntropy = vm.count("printEntropy") == 0 ? false : true;
+  ProgramParameters::lang = vm["lang"].as<std::string>();
+  ProgramParameters::sequenceDelimiterTape = vm["sequenceDelimiterTape"].as<std::string>();
+  ProgramParameters::sequenceDelimiter = vm["sequenceDelimiter"].as<std::string>();
+  ProgramParameters::showFeatureRepresentation = vm["showFeatureRepresentation"].as<bool>();
+
+  const char * MACAON_DIR = std::getenv("MACAON_DIR");
+  std::string slash = "/";
+  ProgramParameters::expPath = MACAON_DIR + slash + ProgramParameters::lang + slash + "bin/" + ProgramParameters::expName + slash;
+
+  ProgramParameters::tmFilename = ProgramParameters::expPath + ProgramParameters::tmName;
+  ProgramParameters::bdFilename = ProgramParameters::expPath + ProgramParameters::bdName;
+  ProgramParameters::mcdFilename = ProgramParameters::mcdName;
+
+  TransitionMachine tm(false);
+
+  BD bd(ProgramParameters::bdFilename, ProgramParameters::mcdFilename);
+  Config config(bd);
+
+  File input(ProgramParameters::input, "r");
+  FILE * inputPtr = input.getDescriptor();
+
+  int isError, errorIndex;
+  while (fscanf(inputPtr, "%d\t%d\n", &isError, &errorIndex) == 2)
+  {
+    config.loadFromFile(input);
+
+    TransitionMachine::State * currentState = tm.getCurrentState();
+    Classifier * classifier = currentState->classifier;
+    config.setCurrentStateName(&currentState->name);
+    Dict::currentClassifierName = classifier->name;
+    classifier->initClassifier(config);
+
+    auto weightedActions = classifier->weightActions(config);
+    std::string pAction = "";
+
+    for (auto & it : weightedActions)
+      if (it.first)
+        if (pAction == "")
+        {
+          pAction = it.second.second;
+          break;
+        }
+
+    Action * action = classifier->getAction(pAction);
+
+    action->apply(config);
+
+  }
+
+  return 0;
+}
+
diff --git a/error_correction/src/macaon_train_error_detector.cpp b/error_correction/src/macaon_train_error_detector.cpp
index 1a621b4..8238cc1 100644
--- a/error_correction/src/macaon_train_error_detector.cpp
+++ b/error_correction/src/macaon_train_error_detector.cpp
@@ -213,30 +213,53 @@ std::map<std::string, std::pair<float, std::pair<float, float> > > getScoreOnDev
     classifierName = classifier->name;
   }
 
+  int pred1Hyp0 = 0;
+  int pred0Hyp1 = 0;
+  int pred0Hyp0 = 0;
+  int pred1Hyp1 = 0;
+
   for (unsigned int i = 0; i < devIsErrors.size(); i++)
   {
     if (devIsErrors[i] == 0)
     {
       counts[classifierName].first++;
       if (predictions[i] == 0)
+      {
         counts[classifierName].second++;
+        pred0Hyp0++;
+      }
+      else
+        pred1Hyp0++;
     }
     else if (i > 0 && devIsErrors[i] == 1 && devIsErrors[i-1] == 0)
     {
       counts[classifierName].first++;
       unsigned int j;
+      bool found = false;
       for (j = i; devIsErrors[j] == 1 && j < devIsErrors.size(); j++)
       {
         if (predictions[j] == 1)
         {
           counts[classifierName].second++;
+          pred1Hyp1++;
+          found = true;
           break;
         }
       }
       i = j;
+      if (!found)
+        pred0Hyp1++;
     }
   }
 
+  fprintf(stderr, "Class 0 nbExemples : %d\n", pred0Hyp0+pred1Hyp0);
+  fprintf(stderr, "Class 0 precision : %.2f\n", 100.0*pred0Hyp0 / (pred0Hyp0+pred1Hyp0));
+  fprintf(stderr, "Class 0 recall : %.2f\n\n", 100.0*pred0Hyp0 / (pred0Hyp0+pred0Hyp1));
+
+  fprintf(stderr, "Class 1 nbExemples : %d\n", pred0Hyp1+pred1Hyp1);
+  fprintf(stderr, "Class 1 precision : %.2f\n", 100.0*pred1Hyp1 / (pred1Hyp1+pred0Hyp1));
+  fprintf(stderr, "Class 1 recall : %.2f\n", 100.0*pred1Hyp1 / (pred1Hyp1+pred1Hyp0));
+
   std::map<std::string, std::pair<float,std::pair<float,float> > > scores;
 
   for (auto & it : counts)
@@ -260,18 +283,15 @@ void printScoresAndSave(FILE * output, std::map< std::string, std::pair<int, int
 
   auto devScores = getScoreOnDev(tm, devConfigs, devIsErrors, devErrorIndexes);
 
-  if (true)
+  for (auto & it : devScores)
   {
-    for (auto & it : devScores)
+    if (bestScores.count(it.first) == 0 || bestScores[it.first] < it.second.first)
     {
-      if (bestScores.count(it.first) == 0 || bestScores[it.first] < it.second.first)
-      {
-        bestScores[it.first] = it.second.first;
-        saved[it.first] = true;
-      }
-      else
-        saved[it.first] = false;
+      bestScores[it.first] = it.second.first;
+      saved[it.first] = true;
     }
+    else
+      saved[it.first] = false;
   }
 
   auto classifiers = tm.getClassifiers();
-- 
GitLab