Skip to content
Snippets Groups Projects
Action.cpp 23 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "Action.hpp"
    
    Franck Dary's avatar
    Franck Dary committed
    #include "Transition.hpp"
    
    Action::Action(Action::Type type, std::function<void(Config & config, Action & action)> apply, std::function<void(Config & config, Action & action)> undo, std::function<bool(const Config & config, const Action & action)> appliable)
    
    {
      this->type = type;
      this->apply = apply;
      this->undo = undo;
      this->appliable = appliable;
    }
    
    Action Action::addLinesIfNeeded(int nbLines)
    {
      auto apply = [nbLines](Config & config, Action &)
      {
    
        while (!config.has(0, config.getWordIndex()+nbLines, 0))
          config.addLines(1);
    
      };
    
      auto undo = [](Config &, Action &)
      {
      };
    
    
      auto appliable = [](const Config &, const Action &)
    
      {
        return true;
      };
    
      return {Type::AddLines, apply, undo, appliable};
    }
    
    Action Action::moveWordIndex(int movement)
    {
      auto apply = [movement](Config & config, Action &)
      {
        config.moveWordIndex(movement);
      };
    
      auto undo = [movement](Config & config, Action &)
      {
    
        config.moveWordIndex(-movement);
    
      auto appliable = [movement](const Config & config, const Action &)
    
        return config.canMoveWordIndex(movement);
    
      };
    
      return {Type::MoveWord, apply, undo, appliable};
    }
    
    
    Action Action::setMultiwordIds(int multiwordSize)
    
    {
      auto apply = [multiwordSize](Config & config, Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        addHypothesisRelative(Config::idColName, Config::Object::Buffer, 0, fmt::format("{}-{}", config.getCurrentWordId()+1, config.getCurrentWordId()+multiwordSize)).apply(config, a);
    
        for (int i = 0; i < multiwordSize; i++)
    
    Franck Dary's avatar
    Franck Dary committed
        {
    
    Franck Dary's avatar
    Franck Dary committed
          addHypothesisRelative(Config::idColName, Config::Object::Buffer, i+1, fmt::format("{}", config.getCurrentWordId()+1+i)).apply(config, a);
          addHypothesisRelative(Config::isMultiColName, Config::Object::Buffer, i+1, Config::EOSSymbol1).apply(config, a);
    
    Franck Dary's avatar
    Franck Dary committed
        }
    
      auto undo = [multiwordSize](Config & config, Action &)
    
      {
        config.getLastNotEmpty(Config::idColName, config.getWordIndex()) = "";
    
        for (int i = 0; i < multiwordSize; i++)
          config.getLastNotEmpty(Config::idColName, config.getWordIndex()+1+i) = "";
    
      };
    
      auto appliable = [](const Config &, const Action &)
      {
        return true;
      };
    
      return {Type::Write, apply, undo, appliable};
    }
    
    
    Action Action::consumeCharacterIndex(util::utf8string consumed)
    
    {
      auto apply = [consumed](Config & config, Action &)
      {
        config.moveCharacterIndex(consumed.size());
      };
    
      auto undo = [consumed](Config & config, Action &)
      {
        config.moveCharacterIndex(-consumed.size());
      };
    
      auto appliable = [consumed](const Config & config, const Action &)
      {
        if (!config.canMoveCharacterIndex(consumed.size()))
          return false;
    
        for (unsigned int i = 0; i < consumed.size(); i++)
          if (!config.hasCharacter(config.getCharacterIndex()+i) or config.getLetter(config.getCharacterIndex()+i) != consumed[i])
            return false;
    
        return true;
      };
    
      return {Type::MoveWord, apply, undo, appliable};
    }
    
    
    Action Action::moveCharacterIndex(int movement)
    {
      auto apply = [movement](Config & config, Action &)
      {
        config.moveCharacterIndex(movement);
      };
    
      auto undo = [movement](Config & config, Action &)
      {
    
        config.moveCharacterIndex(-movement);
    
      auto appliable = [movement](const Config & config, const Action &)
    
        return config.canMoveCharacterIndex(movement);
    
      };
    
      return {Type::MoveChar, apply, undo, appliable};
    }
    
    
    Action Action::addHypothesis(const std::string & colName, std::size_t lineIndex, const std::string & hypothesis)
    {
      auto apply = [colName, lineIndex, hypothesis](Config & config, Action &)
      {
        config.getFirstEmpty(colName, lineIndex) = hypothesis;
      };
    
      auto undo = [colName, lineIndex](Config & config, Action &)
      {
        config.getLastNotEmpty(colName, lineIndex) = "";
      };
    
    
      auto appliable = [](const Config &, const Action &)
    
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Action Action::addToHypothesis(const std::string & colName, std::size_t lineIndex, const std::string & addition)
    {
      auto apply = [colName, lineIndex, addition](Config & config, Action &)
      {
    
        auto currentElems = util::split(config.getLastNotEmptyHypConst(colName, lineIndex).get(), '|');
        currentElems.emplace_back(addition);
    
        std::sort(currentElems.begin(), currentElems.end());
    
        config.getLastNotEmptyHyp(colName, lineIndex) = util::join("|", currentElems);
    
      auto undo = [colName, lineIndex, addition](Config & config, Action &)
    
        auto curElems = util::split(config.getLastNotEmptyHypConst(colName, lineIndex).get(), '|');
        std::vector<std::string> newElems;
        for (auto & elem : curElems)
          if (elem != addition)
            newElems.emplace_back(elem);
    
        config.getLastNotEmptyHyp(colName, lineIndex) = util::join("|", newElems);
    
      };
    
      auto appliable = [colName, lineIndex, addition](const Config & config, const Action &)
      {
        if (!config.has(colName, lineIndex, 0))
          return false;
        auto & current = config.getLastNotEmptyHypConst(colName, lineIndex);
        auto splited = util::split(current.get(), '|');
        for (auto & part : splited)
          if (part == addition)
            return false;
        return true;
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::addToHypothesisRelative(const std::string & colName, Config::Object object, int relativeIndex, const std::string & addition)
    
    {
      auto apply = [colName, object, relativeIndex, addition](Config & config, Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    
        return addToHypothesis(colName, lineIndex, addition).apply(config, a);
      };
    
      auto undo = [colName, object, relativeIndex](Config & config, Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    
        return addToHypothesis(colName, lineIndex, "").undo(config, a);
      };
    
      auto appliable = [colName, object, relativeIndex, addition](const Config & config, const Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        if (!config.hasRelativeWordIndex(object, relativeIndex))
    
          return false;
    
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    
        return addToHypothesis(colName, lineIndex, addition).appliable(config, a);
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::addHypothesisRelative(const std::string & colName, Config::Object object, int relativeIndex, const std::string & hypothesis)
    
    {
      auto apply = [colName, object, relativeIndex, hypothesis](Config & config, Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    Franck Dary's avatar
    Franck Dary committed
        return addHypothesis(colName, lineIndex, hypothesis).apply(config, a);
    
      };
    
      auto undo = [colName, object, relativeIndex](Config & config, Action & a)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    
        return addHypothesis(colName, lineIndex, "").undo(config, a);
      };
    
    
      auto appliable = [colName, object, relativeIndex](const Config & config, const Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
        if (!config.hasRelativeWordIndex(object, relativeIndex))
    
          return false;
    
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
    
    
        return addHypothesis(colName, lineIndex, "").appliable(config, a);
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Action Action::pushWordIndexOnStack()
    {
    
    Franck Dary's avatar
    Franck Dary committed
      auto apply = [](Config & config, Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
        if (config.isTokenPredicted(config.getWordIndex()))
        {
          a.data.emplace_back();
          config.addToStack(config.getWordIndex());
        }
    
    Franck Dary's avatar
    Franck Dary committed
      auto undo = [](Config & config, Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
        if (!a.data.empty())
        {
          config.popStack();
          a.data.pop_back();
        }
    
      auto appliable = [](const Config & config, const Action &)
    
        if (config.hasStack(0) and config.getStack(0) == config.getWordIndex())
          return false;
    
    
        if (config.hasStack(0) and !config.isTokenPredicted(config.getStack(0)))
          return false;
    
    
        return (int)config.getWordIndex() != config.getLastPoppedStack();
    
      };
    
      return {Type::Push, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::popStack(int relIndex)
    
    Franck Dary's avatar
    Franck Dary committed
      auto apply = [relIndex](Config & config, Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
        auto toSave = config.getStack(relIndex);
    
        a.data.push_back(std::to_string(toSave));
    
    Franck Dary's avatar
    Franck Dary committed
        for (int i = 0; relIndex-1-i >= 0; i++)
          config.swapStack(relIndex-i, relIndex-1-i);
    
        config.popStack();
      };
    
    
    Franck Dary's avatar
    Franck Dary committed
      auto undo = [relIndex](Config & config, Action & a)
    
      {
        config.addToStack(std::stoi(a.data.back()));
    
    Franck Dary's avatar
    Franck Dary committed
        for (int i = 0; i+1 <= relIndex; i++)
          config.swapStack(i, i+1);
    
    Franck Dary's avatar
    Franck Dary committed
      auto appliable = [relIndex](const Config & config, const Action &)
    
    Franck Dary's avatar
    Franck Dary committed
        return config.hasStack(relIndex) and config.getStack(relIndex) != config.getWordIndex();
    
      };
    
      return {Type::Pop, apply, undo, appliable}; 
    }
    
    
    Action Action::endWord()
    {
      auto apply = [](Config & config, Action & a)
      {
        config.setCurrentWordId(config.getCurrentWordId()+1);
    
    Franck Dary's avatar
    Franck Dary committed
        addHypothesisRelative(Config::idColName, Config::Object::Buffer, 0, std::to_string(config.getCurrentWordId())).apply(config, a);
    
        
        if (!config.rawInputOnlySeparatorsLeft() and !config.has(0,config.getWordIndex()+1,0))
          config.addLines(1);
      };
    
      auto undo = [](Config & config, Action &)
      {
        config.setCurrentWordId(config.getCurrentWordId()-1);
        config.getLastNotEmpty(Config::idColName, config.getWordIndex()) = "";
      };
    
      auto appliable = [](const Config & config, const Action &)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        if (util::isEmpty(config.getAsFeature("FORM", config.getWordIndex())))
          return false;
        if (!util::isEmpty(config.getAsFeature(Config::idColName, config.getWordIndex())) and config.getAsFeature(Config::isMultiColName, config.getWordIndex()) != Config::EOSSymbol1)
          return false;
    
        return true;
    
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::emptyStack()
    {
      auto apply = [](Config & config, Action & a)
      {
        while (config.hasStack(0))
        {
          a.data.push_back(std::to_string(config.getStack(0)));
          config.popStack();
        }
      };
    
      auto undo = [](Config & config, Action & a)
      {
        while (a.data.size())
        {
          config.addToStack(std::stoi(a.data.back()));
          a.data.pop_back();
        }
      };
    
      auto appliable = [](const Config & config, const Action &)
      {
        return true;
      };
    
      return {Type::Pop, apply, undo, appliable}; 
    }
    
    
    Action Action::ignoreCurrentCharacter()
    {
      auto apply = [](Config & config, Action & a)
      {
        config.moveCharacterIndex(1);
      };
    
      auto undo = [](Config & config, Action & a)
      {
        config.moveCharacterIndex(-1);
      };
    
      auto appliable = [](const Config & config, const Action &)
      {
        return config.hasCharacter(config.getCharacterIndex()) and util::isSeparator(config.getLetter(config.getCharacterIndex())) and config.canMoveCharacterIndex(1);
      };
    
      return {Type::MoveChar, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::assertIsEmpty(const std::string & colName, Config::Object object, int relativeIndex)
    
    {
      auto apply = [](Config &, Action &)
      {
      };
    
      auto undo = [](Config &, Action &)
      {
      };
    
    
    Franck Dary's avatar
    Franck Dary committed
      auto appliable = [colName, object, relativeIndex](const Config & config, const Action &)
    
        try
        {
          if (!config.hasRelativeWordIndex(object, relativeIndex))
            return false;
          auto lineIndex = config.getRelativeWordIndex(object, relativeIndex);
          return util::isEmpty(config.getAsFeature(colName, lineIndex));
        } catch (std::exception & e)
        {
          util::myThrow(fmt::format("colName='{}' object='{}' relativeIndex='{}' {}", colName, object == Config::Object::Stack ? "Stack" : "Buffer", relativeIndex, e.what()));
        }
    
        return false;
    
    Franck Dary's avatar
    Franck Dary committed
      };
    
      return {Type::Check, apply, undo, appliable}; 
    }
    
    Action Action::assertIsNotEmpty(const std::string & colName, Config::Object object, int relativeIndex)
    {
      auto apply = [](Config &, Action &)
      {
      };
    
      auto undo = [](Config &, Action &)
      {
      };
    
      auto appliable = [colName, object, relativeIndex](const Config & config, const Action &)
      {
    
        try
        {
          if (!config.hasRelativeWordIndex(object, relativeIndex))
            return false;
          auto lineIndex = config.getRelativeWordIndex(object, relativeIndex);
          return !util::isEmpty(config.getAsFeature(colName, lineIndex));
        } catch (std::exception & e)
        {
          util::myThrow(fmt::format("colName='{}' object='{}' relativeIndex='{}' {}", colName, object == Config::Object::Stack ? "Stack" : "Buffer", relativeIndex, e.what()));
        }
    
        return false;
    
    Action Action::addCurCharToCurWord()
    {
      auto apply = [](Config & config, Action & a)
      {
        auto & curWord = config.getLastNotEmptyHyp("FORM", config.getWordIndex());
        curWord = fmt::format("{}{}", curWord, config.getLetter(config.getCharacterIndex()));
      };
    
      auto undo = [](Config & config, Action & a)
      {
        auto & curWord = config.getLastNotEmptyHyp("FORM", config.getWordIndex());
        std::string newWord = curWord;
        unsigned int nbToPop = fmt::format("{}", config.getLetter(config.getCharacterIndex())).size();
        for (unsigned int i = 0; i < nbToPop; i++)
          newWord.pop_back();
        curWord = newWord;
      };
    
      auto appliable = [](const Config & config, const Action &)
      {
    
        if (!config.hasCharacter(config.getCharacterIndex()))
          return false;
    
        auto letter = config.getLetter(config.getCharacterIndex());
    
        if (letter == ' ')
          return !util::isEmpty(config.getAsFeature("FORM", config.getWordIndex()));
    
        return !util::isIllegal(letter);
    
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::setRoot(int bufferIndex)
    
    Franck Dary's avatar
    Franck Dary committed
    {
    
    Franck Dary's avatar
    Franck Dary committed
      auto apply = [bufferIndex](Config & config, Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(Config::Object::Buffer, bufferIndex);
    
    Franck Dary's avatar
    Franck Dary committed
        int rootIndex = -1;
    
    
    Franck Dary's avatar
    Franck Dary committed
        for (int i = lineIndex; true; --i)
    
    Franck Dary's avatar
    Franck Dary committed
        {
          if (!config.has(0, i, 0))
          {
            if (i < 0)
              break;
            util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
          }
    
    Franck Dary's avatar
    Franck Dary committed
          if (!config.isTokenPredicted(i))
    
    Franck Dary's avatar
    Franck Dary committed
            continue;
    
    
    Franck Dary's avatar
    Franck Dary committed
          if (config.getAsFeature(Config::EOSColName, i) == Config::EOSSymbol1)
    
    Franck Dary's avatar
    Franck Dary committed
            break;
    
    
    Franck Dary's avatar
    Franck Dary committed
          if (util::isEmpty(config.getAsFeature(Config::headColName, i)))
    
    Franck Dary's avatar
    Franck Dary committed
          {
            rootIndex = i;
            a.data.push_back(std::to_string(i));
          }
        }
    
    
    Franck Dary's avatar
    Franck Dary committed
        for (int i = lineIndex; true; --i)
    
    Franck Dary's avatar
    Franck Dary committed
        {
          if (!config.has(0, i, 0))
          {
            if (i < 0)
              break;
            util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
          }
    
    Franck Dary's avatar
    Franck Dary committed
          if (!config.isTokenPredicted(i))
    
    Franck Dary's avatar
    Franck Dary committed
            continue;
    
    
    Franck Dary's avatar
    Franck Dary committed
          if (config.getAsFeature(Config::EOSColName, i) == Config::EOSSymbol1)
    
    Franck Dary's avatar
    Franck Dary committed
            break;
    
    
    Franck Dary's avatar
    Franck Dary committed
          if (util::isEmpty(config.getAsFeature(Config::headColName, i)))
    
    Franck Dary's avatar
    Franck Dary committed
          {
            if (i == rootIndex)
            {
              config.getFirstEmpty(Config::headColName, i) = "0";
              config.getFirstEmpty(Config::deprelColName, i) = "root";
            }
            else
            {
    
              config.getFirstEmpty(Config::headColName, i) = std::to_string(rootIndex);
    
    Franck Dary's avatar
    Franck Dary committed
            }
          }
        }
    
      };
    
      auto undo = [](Config & config, Action & a)
      {
        while (a.data.size())
        {
          config.getLastNotEmptyHyp(Config::headColName, std::stoi(a.data.back())) = "";
          a.data.pop_back();
        }
      };
    
    
    Franck Dary's avatar
    Franck Dary committed
      auto appliable = [bufferIndex](const Config & config, const Action &)
    
    Franck Dary's avatar
    Franck Dary committed
      {
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(Config::Object::Buffer, bufferIndex);
        return config.has(0,lineIndex,0) and config.isTokenPredicted(lineIndex) and config.getAsFeature(Config::isMultiColName, lineIndex) != Config::EOSSymbol1;
    
    Franck Dary's avatar
    Franck Dary committed
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::updateIds(int bufferIndex)
    
    Franck Dary's avatar
    Franck Dary committed
      auto apply = [bufferIndex](Config & config, Action & a)
    
    Franck Dary's avatar
    Franck Dary committed
        int lineIndex = config.getRelativeWordIndex(Config::Object::Buffer, bufferIndex);
    
        int firstIndexOfSentence = -1;
    
    Franck Dary's avatar
    Franck Dary committed
        int lastSentId = -1;
        for (int i = lineIndex; true; --i)
    
        {
          if (!config.has(0, i, 0))
          {
            if (i < 0)
              break;
            util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
          }
    
          if (config.isComment(i) || config.isEmptyNode(i))
    
            continue;
    
          if (config.getLastNotEmptyHypConst(Config::EOSColName, i) == Config::EOSSymbol1)
    
    Franck Dary's avatar
    Franck Dary committed
          {
            lastSentId = std::stoi(config.getAsFeature(Config::sentIdColName, i));
    
    Franck Dary's avatar
    Franck Dary committed
          }
    
    
          firstIndexOfSentence = i;
        }
    
        if (firstIndexOfSentence < 0)
          util::myThrow("could not find any token in current sentence");
    
    
    Franck Dary's avatar
    Franck Dary committed
        for (int i = firstIndexOfSentence, currentId = 1; i <= lineIndex; ++i)
    
          if (config.isComment(i) || config.isEmptyNode(i))
    
    Franck Dary's avatar
    Franck Dary committed
          if (config.isMultiwordPredicted(i))
            config.getFirstEmpty(Config::idColName, i) = fmt::format("{}-{}", currentId, currentId+config.getMultiwordSizePredicted(i));
    
          else
            config.getFirstEmpty(Config::idColName, i) = fmt::format("{}", currentId++);
    
    Franck Dary's avatar
    Franck Dary committed
    
          config.getFirstEmpty(Config::sentIdColName, i) = fmt::format("{}", lastSentId+1);
    
        }
      };
    
      auto undo = [](Config & config, Action & a)
      {
        // TODO : undo this
      };
    
      auto appliable = [](const Config &, const Action &)
      {
        return true;
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::attach(Config::Object governorObject, int governorIndex, Config::Object dependentObject, int dependentIndex)
    
    {
      auto apply = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a)
      {
    
        long govIndex = config.getRelativeWordIndex(governorObject, governorIndex);
    
    Franck Dary's avatar
    Franck Dary committed
        long depIndex = config.getRelativeWordIndex(dependentObject, dependentIndex);
    
        addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, std::to_string(govIndex)).apply(config, a);
    
        addToHypothesisRelative(Config::childsColName, governorObject, governorIndex, std::to_string(depIndex)).apply(config, a);
    
        a.data.emplace_back(std::to_string(config.getLastAttached()));
        config.setLastAttached(depIndex);
    
      };
    
      auto undo = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a)
      {
        addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, "").undo(config, a);
    
        addToHypothesisRelative(Config::childsColName, governorObject, governorIndex, "").apply(config, a);
    
        config.setLastAttached(std::stoi(a.data.back()));
        a.data.pop_back();
    
      };
    
      auto appliable = [governorObject, governorIndex, dependentObject, dependentIndex](const Config & config, const Action & action)
      {
    
    Franck Dary's avatar
    Franck Dary committed
        if (!config.hasRelativeWordIndex(governorObject, governorIndex) or !config.hasRelativeWordIndex(dependentObject, dependentIndex))
          return false;
    
    Franck Dary's avatar
    Franck Dary committed
        long govLineIndex = config.getRelativeWordIndex(governorObject, governorIndex);
        long depLineIndex = config.getRelativeWordIndex(dependentObject, dependentIndex);
    
        if (!config.isTokenPredicted(govLineIndex) or !config.isTokenPredicted(depLineIndex))
          return false;
    
    
    Franck Dary's avatar
    Franck Dary committed
        // Check if dep and head belongs to the same sentence
        if (config.getAsFeature(Config::sentIdColName, govLineIndex) != config.getAsFeature(Config::sentIdColName, depLineIndex))
          return false;
    
    
        // Check if dep is not already attached
        if (!util::isEmpty(config.getAsFeature(Config::headColName, depLineIndex)))
          return false;
    
    
        // Check for cycles
        while (govLineIndex != depLineIndex)
        {
          try
          {
    
    Franck Dary's avatar
    Franck Dary committed
            govLineIndex = std::stoi(config.getAsFeature(Config::headColName, govLineIndex));
    
          } catch(std::exception &) {return true;}
        }
    
        return false;
    
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::split(int index)
    {
      auto apply = [index](Config & config, Action &)
      {
        Transition * t = config.getAppliableSplitTransitions()[index];
        t->apply(config);
      };
    
      auto undo = [](Config &, Action &)
      {
        //TODO : undo this
      };
    
      auto appliable = [index](const Config & config, const Action &)
      {
        auto & transitions = config.getAppliableSplitTransitions();
    
        if (index < 0 or index >= (int)transitions.size())
          return false;
    
        Transition * t = transitions[index];
        return t->appliable(config);
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Franck Dary's avatar
    Franck Dary committed
    Action Action::setRootUpdateIdsEmptyStackIfSentChanged()
    {
      auto apply = [](Config & config, Action & a)
      {
        int lineIndex = config.getWordIndex();
        int rootIndex = -1;
        int lastSentId = -1;
        int firstIndexOfSentence = lineIndex;
    
        if (config.getAsFeature(Config::EOSColName, lineIndex) != Config::EOSSymbol1)
          return;
    
        for (int i = lineIndex-1; true; --i)
        {
          if (!config.has(0, i, 0))
          {
            if (i < 0)
              break;
            util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
          }
          if (!config.isTokenPredicted(i))
            continue;
    
          if (config.getAsFeature(Config::EOSColName, i) == Config::EOSSymbol1)
          {
            lastSentId = std::stoi(config.getAsFeature(Config::sentIdColName, i));
            break;
          }
    
          if (util::isEmpty(config.getAsFeature(Config::headColName, i)))
            rootIndex = i;
    
          firstIndexOfSentence = i;
        }
    
        if (firstIndexOfSentence < 0)
          util::myThrow("could not find any token in current sentence");
    
        for (int i = firstIndexOfSentence; i <= lineIndex; ++i)
        {
          if (!config.has(0, i, 0))
          {
            if (i < 0)
              break;
            util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
          }
          if (!config.isTokenPredicted(i))
            continue;
    
          if (util::isEmpty(config.getAsFeature(Config::headColName, i)))
          {
            if (i == rootIndex)
            {
              config.getFirstEmpty(Config::headColName, i) = "0";
              config.getFirstEmpty(Config::deprelColName, i) = "root";
            }
            else
            {
              config.getFirstEmpty(Config::headColName, i) = std::to_string(rootIndex);
            }
          }
        }
    
        for (int i = firstIndexOfSentence, currentId = 1; i <= lineIndex; ++i)
        {
          if (config.isComment(i) || config.isEmptyNode(i))
            continue;
    
          if (config.isMultiwordPredicted(i))
            config.getFirstEmpty(Config::idColName, i) = fmt::format("{}-{}", currentId, currentId+config.getMultiwordSizePredicted(i));
          else
            config.getFirstEmpty(Config::idColName, i) = fmt::format("{}", currentId++);
    
          config.getFirstEmpty(Config::sentIdColName, i) = fmt::format("{}", lastSentId+1);
        }
    
        while (config.hasStack(0))
          config.popStack();
      };
    
      auto undo = [](Config & config, Action & a)
      {
        //TODO undo this
      };
    
      auto appliable = [](const Config & config, const Action &)
      {
        int lineIndex = config.getWordIndex();
        return config.has(0,lineIndex,0);
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }
    
    
    Action Action::deprel(std::string value)
    {
      auto apply = [value](Config & config, Action & a)
      {
        addHypothesis(Config::deprelColName, config.getLastAttached(), value).apply(config, a);
      };
    
      auto undo = [](Config & config, Action & a)
      {
        addHypothesis(Config::deprelColName, config.getLastAttached(), "").undo(config, a);
      };
    
      auto appliable = [](const Config & config, const Action & action)
      {
        return config.has(0,config.getLastAttached(),0);
      };
    
      return {Type::Write, apply, undo, appliable}; 
    }