Newer
Older
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 &)
{
auto appliable = [movement](const Config & config, const Action &)
return config.canMoveWordIndex(movement);
};
return {Type::MoveWord, apply, undo, appliable};
}
Franck Dary
committed
Action Action::setMultiwordIds(int multiwordSize)
{
auto apply = [multiwordSize](Config & config, Action & a)
{
addHypothesisRelative(Config::idColName, Config::Object::Buffer, 0, fmt::format("{}-{}", config.getCurrentWordId()+1, config.getCurrentWordId()+multiwordSize)).apply(config, a);
Franck Dary
committed
for (int i = 0; i < multiwordSize; i++)
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
committed
auto undo = [multiwordSize](Config & config, Action &)
{
config.getLastNotEmpty(Config::idColName, config.getWordIndex()) = "";
Franck Dary
committed
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 &)
{
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) = "";
};
Franck Dary
committed
auto appliable = [](const Config &, const Action &)
Franck Dary
committed
return true;
};
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 & current = config.getLastNotEmptyHyp(colName, lineIndex);
current = util::isEmpty(current) ? addition : current.get() + '|' + addition;
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
};
auto undo = [colName, lineIndex](Config & config, Action &)
{
std::string newValue = config.getLastNotEmpty(colName, lineIndex);
while (!newValue.empty() and newValue.back() == '|')
newValue.pop_back();
if (!newValue.empty())
newValue.pop_back();
config.getLastNotEmpty(colName, lineIndex) = newValue;
};
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};
}
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)
{
int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
return addToHypothesis(colName, lineIndex, addition).apply(config, a);
};
auto undo = [colName, object, relativeIndex](Config & config, Action & a)
{
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)
{
int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
return addToHypothesis(colName, lineIndex, addition).appliable(config, a);
};
return {Type::Write, apply, undo, appliable};
}
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)
{
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)
int lineIndex = config.getRelativeWordIndex(object, relativeIndex);
return addHypothesis(colName, lineIndex, "").appliable(config, a);
};
return {Type::Write, apply, undo, appliable};
}
Action Action::pushWordIndexOnStack()
{
if (config.isTokenPredicted(config.getWordIndex()))
{
a.data.emplace_back();
config.addToStack(config.getWordIndex());
}
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};
}
auto apply = [relIndex](Config & config, Action & a)
a.data.push_back(std::to_string(toSave));
for (int i = 0; relIndex-1-i >= 0; i++)
config.swapStack(relIndex-i, relIndex-1-i);
auto undo = [relIndex](Config & config, Action & a)
{
config.addToStack(std::stoi(a.data.back()));
for (int i = 0; i+1 <= relIndex; i++)
config.swapStack(i, i+1);
auto appliable = [relIndex](const Config & config, const Action &)
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);
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 &)
{
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};
}
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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};
}
Action Action::assertIsEmpty(const std::string & colName, Config::Object object, int relativeIndex)
Franck Dary
committed
{
auto apply = [](Config &, Action &)
{
};
auto undo = [](Config &, Action &)
{
};
auto appliable = [colName, object, relativeIndex](const Config & config, const Action &)
Franck Dary
committed
{
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;
};
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;
Franck Dary
committed
};
return {Type::Check, apply, undo, appliable};
}
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};
}
int lineIndex = config.getRelativeWordIndex(Config::Object::Buffer, bufferIndex);
{
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.getAsFeature(Config::EOSColName, i) == Config::EOSSymbol1)
if (util::isEmpty(config.getAsFeature(Config::headColName, i)))
{
rootIndex = i;
a.data.push_back(std::to_string(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.getAsFeature(Config::EOSColName, i) == Config::EOSSymbol1)
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);
}
}
}
};
auto undo = [](Config & config, Action & a)
{
while (a.data.size())
{
config.getLastNotEmptyHyp(Config::headColName, std::stoi(a.data.back())) = "";
a.data.pop_back();
}
};
auto appliable = [bufferIndex](const Config & config, const Action &)
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;
};
return {Type::Write, apply, undo, appliable};
}
int lineIndex = config.getRelativeWordIndex(Config::Object::Buffer, bufferIndex);
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)
{
lastSentId = std::stoi(config.getAsFeature(Config::sentIdColName, i));
firstIndexOfSentence = i;
}
if (firstIndexOfSentence < 0)
util::myThrow("could not find any token in current sentence");
for (int i = firstIndexOfSentence, currentId = 1; i <= lineIndex; ++i)
if (config.isComment(i) || config.isEmptyNode(i))
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);
}
};
auto undo = [](Config & config, Action & a)
{
// TODO : undo this
};
auto appliable = [](const Config &, const Action &)
{
return true;
};
return {Type::Write, apply, undo, appliable};
}
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);
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)
{
if (!config.hasRelativeWordIndex(governorObject, governorIndex) or !config.hasRelativeWordIndex(dependentObject, dependentIndex))
return false;
long govLineIndex = config.getRelativeWordIndex(governorObject, governorIndex);
long depLineIndex = config.getRelativeWordIndex(dependentObject, dependentIndex);
if (!config.isTokenPredicted(govLineIndex) or !config.isTokenPredicted(depLineIndex))
return false;
// 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 false;
};
return {Type::Write, apply, undo, appliable};
}
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
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};
}
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
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};
}