Skip to content
Snippets Groups Projects
Action.cpp 29.7 KiB
Newer Older
#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::addHypothesisRelativeRelaxed(const std::string & colName, Config::Object object, int relativeIndex, const std::string & hypothesis)
{
  auto apply = [colName, object, relativeIndex, hypothesis](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(object, relativeIndex);

    return addHypothesis(colName, lineIndex, hypothesis).apply(config, a);
  };

  auto undo = [colName, object, relativeIndex](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(object, relativeIndex);

    return addHypothesis(colName, lineIndex, "").undo(config, a);
  };

  auto appliable = [colName, object, relativeIndex](const Config & config, const Action & a)
  {
    return true;
  };

  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
//      {
//        govLineIndex = std::stoi(config.getAsFeature(Config::headColName, govLineIndex));
//      } catch(std::exception &) {return true;}
//    }
  };

  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 = lineIndex;
Franck Dary's avatar
Franck Dary committed
    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;
    }

    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}; 
}

Franck Dary's avatar
Franck Dary committed
Action Action::transformSuffix(std::string fromCol, Config::Object fromObj, int fromIndex, std::string toCol, Config::Object toObj, int toIndex, util::utf8string toRemove, util::utf8string toAdd)
{
  auto apply = [fromCol, fromObj, fromIndex, toCol, toObj, toIndex, toRemove, toAdd](Config & config, Action & a)
  {
    int fromLineIndex = config.getRelativeWordIndex(fromObj, fromIndex);
    int toLineIndex = config.getRelativeWordIndex(toObj, toIndex);

    if (toRemove.empty() and toAdd.empty())
    {
      addHypothesis(toCol, toLineIndex, config.getAsFeature(fromCol, fromLineIndex).get()).apply(config, a);
      return;
    }

    util::utf8string res = util::splitAsUtf8(util::lower(config.getAsFeature(fromCol, fromLineIndex).get()));
    for (unsigned int i = 0; i < toRemove.size(); i++)
      res.pop_back();
    for (auto & letter : toAdd)
      res.push_back(letter);
    addHypothesis(toCol, toLineIndex, fmt::format("{}", res)).apply(config, a);
  };

  auto undo = [toCol, toObj, toIndex](Config & config, Action & a)
  {
    int toLineIndex = config.getRelativeWordIndex(toObj, toIndex);
    addHypothesis(toCol, toLineIndex, "").undo(config, a);
  };

  auto appliable = [fromCol, fromObj, fromIndex, toCol, toObj, toIndex, toRemove, toAdd](const Config & config, const Action & a)
  {
    if (!config.hasRelativeWordIndex(fromObj, fromIndex) or !config.hasRelativeWordIndex(toObj, toIndex))
      return false;

    int fromLineIndex = config.getRelativeWordIndex(fromObj, fromIndex);
    int toLineIndex = config.getRelativeWordIndex(toObj, toIndex);
    util::utf8string res = util::splitAsUtf8(util::lower(config.getAsFeature(fromCol, fromLineIndex).get()));
    if (res.size() < toRemove.size())
      return false;

    for (unsigned int i = 0; i < toRemove.size(); i++)
    {
      if (res.back() != toRemove[toRemove.size()-1-i])
        return false;
      res.pop_back();
    }

    for (auto & letter : toAdd)
      res.push_back(letter);

    return addHypothesis(toCol, toLineIndex, fmt::format("{}", res)).appliable(config, a);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::uppercase(std::string col, Config::Object obj, int index)
{
  auto apply = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto res = util::upper(config.getAsFeature(col, lineIndex));

    addHypothesis(col, lineIndex, res).apply(config, a);
  };

  auto undo = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    addHypothesis(col, lineIndex, "").undo(config, a);
  };

  auto appliable = [col, obj, index](const Config & config, const Action & a)
  {
    if (!config.hasRelativeWordIndex(obj, index))
      return false;

    int lineIndex = config.getRelativeWordIndex(obj, index);

    return addHypothesis(col, lineIndex, "").appliable(config, a);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::uppercaseIndex(std::string col, Config::Object obj, int index, int inIndex)
{
  auto apply = [col, obj, index, inIndex](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto res = util::splitAsUtf8(config.getAsFeature(col, lineIndex).get());
    util::upper(res[inIndex]);

    addHypothesis(col, lineIndex, fmt::format("{}", res)).apply(config, a);
  };

  auto undo = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto & value = config.getLastNotEmptyHyp(col, lineIndex);
    auto res = util::splitAsUtf8(value.get());
    value = fmt::format("{}", res);
  };

  auto appliable = [col, obj, index, inIndex](const Config & config, const Action & a)
  {
    if (!config.hasRelativeWordIndex(obj, index))
      return false;

    int lineIndex = config.getRelativeWordIndex(obj, index);

    if ((int)util::splitAsUtf8(config.getAsFeature(col, lineIndex).get()).size() <= inIndex)
      return false;

    return addHypothesis(col, lineIndex, "").appliable(config, a);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::lowercase(std::string col, Config::Object obj, int index)
{
  auto apply = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto res = util::lower(config.getAsFeature(col, lineIndex));

    addHypothesis(col, lineIndex, res).apply(config, a);
  };

  auto undo = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    addHypothesis(col, lineIndex, "").undo(config, a);
  };

  auto appliable = [col, obj, index](const Config & config, const Action & a)
  {
    if (!config.hasRelativeWordIndex(obj, index))
      return false;

    int lineIndex = config.getRelativeWordIndex(obj, index);

    return addHypothesis(col, lineIndex, "").appliable(config, a);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::lowercaseIndex(std::string col, Config::Object obj, int index, int inIndex)
{
  auto apply = [col, obj, index, inIndex](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto res = util::splitAsUtf8(config.getAsFeature(col, lineIndex).get());
    util::lower(res[inIndex]);

    addHypothesis(col, lineIndex, fmt::format("{}", res)).apply(config, a);
  };

  auto undo = [col, obj, index](Config & config, Action & a)
  {
    int lineIndex = config.getRelativeWordIndex(obj, index);
    auto & value = config.getLastNotEmptyHyp(col, lineIndex);
    auto res = util::splitAsUtf8(value.get());
    value = fmt::format("{}", res);
  };

  auto appliable = [col, obj, index, inIndex](const Config & config, const Action & a)
  {
    if (!config.hasRelativeWordIndex(obj, index))
      return false;

    int lineIndex = config.getRelativeWordIndex(obj, index);

    if ((int)util::splitAsUtf8(config.getAsFeature(col, lineIndex).get()).size() <= inIndex)
      return false;

    return addHypothesis(col, lineIndex, "").appliable(config, a);
  };