19#include <boost/tuple/tuple.hpp>
26#include <QCryptographicHash>
33namespace LinguisticProcessing {
39#define DEFAULT_MAXDEPTHSTACK 100
40#define DEFAULT_MAXTRANSITIONSEXPLORED 1000
41#define DEFAULT_MAXNBRESULTS 50
42#define DEFAULT_MAXRESULTSIZE 200
66 m_searchStructures(0),
67 m_deterministic(false),
73 m_numberStates(nbStates),
74 m_finalStates(nbStates,false),
75 m_transitions(nbStates),
76 m_searchStructures(nbStates,0),
77 m_deterministic(false),
126 std::vector<TransitionSearchStructure<Transition>*>::const_iterator
127 it=a.m_searchStructures.begin(),
128 it_end=a.m_searchStructures.end();
129 for (; it!=it_end;it++) {
144 std::vector<TransitionSearchStructure<Transition>*>::iterator
147 for (; it!=it_end;it++) {
174 vector<Tstate> finals(0);
202 Tstate currentState(state);
204 for (uint64_t i(0); i<
m_transitions[currentState].size(); i++) {
205 if (
m_transitions[currentState][i].transitionUnit()->isEpsilonTransition()) {
215 std::cerr <<
"Automaton::initializeSearchStructure " << (
void*)
this << std::endl;
218 std::cerr <<
"Automaton::initializeSearchStructure macro " << (
void*)macro << std::endl;
219 std::cerr <<
"Automaton::initializeSearchStructure micro " << (
void*)micro << std::endl;
238 std::vector<DFFSPos>& matchingTransitions,
242 if (token ==
nullptr) {
244 LIMA_EXCEPTION(
"Automaton::getMatchingTransitions no token for vertex " << vertex);
247 if (data ==
nullptr) {
249 LIMA_EXCEPTION(
"Automaton::getMatchingTransitions no morphosyntactic data for vertex " << vertex);
265 matchingTransitions.clear();
266 vector<Transition>::const_iterator
270 for (; trans!=trans_end; trans++) {
276 deque<LinguisticGraphVertex> noVertices;
277 DFFSPos newPair(noVertices,
nullptr);
279 bool match=(*trans).transitionUnit()->compare(graph,vertex,analysis,token,data);
288 deque<LinguisticGraphVertex> vertices;
289 match = gtrans->
matchPath(graph, vertex, limit, searchGraph, analysis, token, vertices, data);
294 std::copy(vertices.begin(),vertices.end(),std::ostream_iterator<int>(oss,
"-"));
295 LDEBUG <<
"GazeteerTransition returned a match with vertices " << oss.str();
297 newPair =
DFFSPos(vertices,&(*trans));
301 deque<LinguisticGraphVertex> singleton(1,vertex);
302 newPair =
DFFSPos(singleton,&(*trans));
304 if ((*trans).transitionUnit()->negative()) {
308 matchingTransitions.push_back(newPair);
312 LDEBUG <<
"Automaton::getMatchingTransitions: found" << matchingTransitions.size() <<
"matching transitions";
314 return (!matchingTransitions.empty());
319 LDEBUG <<
"Automaton::getMatchingTransitions: search structure initialized find";
323 findMatchingTransitions2(graph,vertex,limit,searchGraph,analysis,token,data,matchingTransitions);
342 if (nbElt1 > nbElt2) {
345 if (nbElt1 == nbElt2) {
347 uint64_t size1=m1.size();
348 uint64_t size2=m2.size();
352 else if (size1 == size2) {
355 for (uint64_t i(0); i<size1; i++) {
356 if (m1[i].getVertex() > m2[i].getVertex()) {
359 if (m1[i].getVertex() < m2[i].getVertex()) {
373 for (
auto i = x.first.begin(); i != x.first.end(); i++) {
374 if (i != x.first.begin())
378 os <<
" transitions=";
379 if (x.second == NULL)
399 m_searchGraph(searchGraph),
404 uint64_t
size()
const {
return m_stack.size(); }
405 bool empty()
const {
return m_stack.empty(); }
407 {
return (v==m_limit);}
410 {
return (v==m_searchGraph->endOfGraph(m_graph)); }
423 struct DFSStackElement {
424 DFSStackElement( std::vector<DFFSPos>& matchingTransitions):
425 m_transitions(matchingTransitions),
426 m_transition(matchingTransitions.begin())
430 DFSStackElement(
const DFSStackElement& elt):
431 m_transitions(elt.m_transitions),
432 m_transition(m_transitions.begin())
436 ~DFSStackElement() {}
438 void debug_output(std::ostream& os)
const {
439 for (
auto i = m_transitions.begin(); i != m_transitions.end(); i++) {
440 if (i != m_transitions.begin())
446 std::vector<DFFSPos > m_transitions;
448 std::vector<DFFSPos>::const_iterator m_transition;
451 std::vector<DFSStackElement> m_stack;
452 const Automaton& m_automaton;
454 SearchGraph* m_searchGraph;
460 os <<
"m_stack = {\n";
462 for (
auto i = x.m_stack.begin(); i != x.m_stack.end(); i++) {
463 if (i != x.m_stack.begin())
474 std::stringstream ss;
476 os << ss.str().c_str();
488 return *(m_stack.back().m_transition);
496 m_stack.back().m_transition++;
497 if (m_stack.back().m_transition==
498 m_stack.back().m_transitions.end()) {
572 LDEBUG <<
"Automaton:DFSSTack: pushing " << vertex <<
";" << state;
575 if (isLimitVertex(vertex)) {
579 if (! m_automaton.hasTransitionsState(state)) {
585 std::vector<DFSStackElement> tmpStack;
588 m_searchGraph->findNextVertices(m_graph.getGraph(),vertex);
591 while (m_searchGraph->getNextVertex(m_graph.getGraph(),nextVertex)) {
600 if (! isEndVertex(nextVertex)) {
602 std::vector<DFFSPos> matchingTransitions(0);
605 LDEBUG <<
"Automaton:get matching transitions from state "
606 << state <<
" for vertex " << nextVertex;
611 m_searchGraph,state,matchingTransitions,limit)) {
627 tmpStack.push_back(DFSStackElement(matchingTransitions));
638 m_searchGraph->clear();
640 if (tmpStack.empty()) {
643 m_stack.insert(m_stack.end(),tmpStack.rbegin(),tmpStack.rend());
672 results,checkList,forward,
673 backward,sense,controlParams);
677 for (
auto & res : results ) {
678 if (res.first.hasDuplicateElements()) {
683 LERROR <<
"duplicate elements in RecognizerMatch:"
684 << res.first.getString();
689 longestMatch=res.first;
690 checkList=res.second;
698 std::reverse(longestMatch.begin(),longestMatch.end());
727 DFSStack forwardSearchStack(*
this,graph,
731 begin, limit, analysis,
742 DFSStack backwardSearchStack(*
this,graph,
746 begin, limit, analysis,
770 LDEBUG <<
"Automaton: testing from state " << firstState;
781 results.insert(make_pair(currentMatch,checkList));
784 if (S.isEndVertex(beginVertex)) {
788 return (!results.empty());
798 S.push(beginVertex,firstState,analysis,limitVertex);
803 bool backtrack(
false);
806 vector<uint64_t> backtrackDepth;
807 backtrackDepth.push_back(0);
814 while (! S.empty()) {
828 LWARN <<
"MaxDepthStack exceeded in automaton search: ignore rest of search";
829 return (!results.empty());
833 LWARN <<
"MaxTransitionsExplored exceeded in automaton search: ignore rest of search";
834 return (!results.empty());
838 DFFSPos const & dffsPos = S.top();
839 vertex = dffsPos.first.front();
840 transition = dffsPos.second;
845 if (backtrackDepth.empty()) {
847 LWARN <<
"Automaton: should not be here! "
848 <<
"backtrack stack empty: abort search";
849 return (!results.empty());
852 uint64_t depth=backtrackDepth.back();
860 if (currentMatch.size() < depth) {
862 LWARN <<
"Automaton: should not be here! "
863 <<
"backtrack depth larger than current match size: abort search";
864 return (!results.empty());
866 for (uint64_t i(0); i<depth; i++) {
869 backtrackDepth.pop_back();
870 if (backtrackDepth.empty()) {
871 backtrackDepth.push_back(0);
880 bool lastTransitionWithThisVertex=S.pop();
886 LDEBUG <<
"Automaton: testing vertex " << vertex <<
" with transition " << *trans;
896 LDEBUG <<
"Automaton: -> match found";
901 std::deque<LinguisticGraphVertex>::const_iterator vIt = dffsPos.first.begin();
902 for( ; vIt != dffsPos.first.end() ; vIt++ ) {
912 if (! lastTransitionWithThisVertex) {
916 backtrackDepth.push_back(dffsPos.first.size());
919 backtrackDepth.back()+=dffsPos.first.size();
931 LWARN <<
"maxResultSize exceeded in automaton search: ignore result";
935 LDEBUG <<
"Automaton: add possible match: " << currentMatch;
937 results.insert(make_pair(currentMatch,checkList));
940 LWARN <<
"maxNbResults exceeded in automaton search: ignore rest of search";
941 return (!results.empty());
962 if (!S.push(dffsPos.first.back(),nextState,analysis,limitVertex)) {
973 else if (lastTransitionWithThisVertex) {
978 return (!results.empty());
1009 vector<Transition>::iterator
1012 for (; it!=it_end; it++) {
1013 if (!(*it).transitionUnit()->isEpsilonTransition()) {
1022 for (; it!=it_end; it++) {
1023 if (!(*it).transitionUnit()->isEpsilonTransition()) {
1027 LDEBUG <<
"Automaton::addTransition( " << (*it).transitionUnit() <<
")";
1042 std::cerr <<
"Warning: removeState not yet implemented..." << endl;
1047 vector<Transition>::iterator i;
1049 if (*(i->transitionUnit()) == transition) {
1076 if (!subset.empty()) {
1077 SubSet::const_iterator
1078 state=subset.begin(),
1079 state_end=subset.end();
1082 for (; state!=state_end; state++) {
1083 oss <<
"," << *state;
1100 SubSet::const_iterator
1103 for (; state!=state_end; state++) {
1112 vector<TransitionUnit*> alphabet;
1113 vector< Automaton::SubSet >
subsets;
1120 LDEBUG <<
"Automaton::subsets():\n";
1123 for (uint64_t i(0); i<alphabet.size(); i++) {
1124 oss << *(alphabet[i]) <<
"\n";
1137 firstSubSet.insert(0);
1138 subsets.push_back(firstSubSet);
1140 for (uint64_t i(0); i<detFA.numberOfStates(); i++) {
1141 for (uint64_t j(0); j<alphabet.size(); j++) {
1142 currentSubset.clear();
1148 if (currentSubset.size()) {
1151 bool existingSubset(
false);
1152 for (uint64_t k(0); k<
subsets.size(); k++) {
1153 if (currentSubset ==
subsets[k]) {
1156 detFA.addTransition(i,k,t);
1157 existingSubset=
true;
1163 if (! existingSubset) {
1164 Tstate lastState=detFA.addState();
1165 if (
isFinalSubset(currentSubset)) { detFA.makeFinal(lastState); }
1166 subsets.push_back(currentSubset);
1169 detFA.addTransition(i,lastState,t);
1179 for (uint64_t i(0); i< alphabet.size(); i++) {
1185 detFA.setDeterministic(
true);
1197 std::vector<std::pair<LimaString,Constraint> >::const_iterator constraintIt = actionsWithOneArgument.begin();
1200 LDEBUG <<
"Automaton::setActionHash: compute hash for " << t;
1202 for( ; constraintIt != actionsWithOneArgument.end() ; constraintIt++ ) {
1205 std::string elementId = (constraintIt->first).toStdString();
1207 LDEBUG <<
"Automaton::setActionHash: compare to " << elementId;
1209 if( !(elementId.compare(t.
getId())) )
1217 QCryptographicHash hashFunctor(QCryptographicHash::Md5);
1218 hashFunctor.addData(signature.toUtf8());
1219 QString hashValue = QString(hashFunctor.result());
1223 LDEBUG <<
"Automaton::setActionHash: set hash to " << hashValue;
1233 vector<TransitionUnit*> alphabet(0);
1234 bool alreadyCollected;
1238 if (
m_transitions[i][j].transitionUnit()->isEpsilonTransition()) {
continue; }
1240 alreadyCollected=
false;
1241 for (uint64_t k(0); k<alphabet.size(); k++) {
1242 if (*(
m_transitions[i][j].transitionUnit()) == *(alphabet[k])) {
1243 alreadyCollected=
true;
1247 if (! alreadyCollected) {
1249 alphabet.push_back(t);
1260 SubSet& reachable)
const {
1261 SubSet::const_iterator
1262 state=states.begin(),
1263 state_end=states.end();
1265 for (; state!=state_end; state++) {
1272 SubSet& reachable)
const {
1274 std::vector<Transition>::const_iterator
1279 for (; transition!=transition_end; transition++) {
1280 Tstate nextState=transition->nextState();
1281 if (*(transition->transitionUnit()) == t) {
1282 reachable.insert(nextState);
1285 else if (transition->transitionUnit()->isEpsilonTransition()) {
1296 Tstate newValueInitialState;
1306 reverseAutomaton.makeFinal(newValueInitialState);
1310 for (uint64_t i(0); i<finals.size(); i++) {
1323 if (initial == 0) { initial = newValueInitialState; }
1324 if (
final == 0) {
final = newValueInitialState; }
1325 reverseAutomaton.addTransition(initial,
final,
1332 reverseAutomaton = reverseAutomaton.subsets();
1335 return reverseAutomaton;
1364 for (uint64_t i(0); i<a.numberOfStates(); i++) {
1365 if (a.isFinalState(i)) { os << i <<
" [final]" << endl; }
1366 for (uint64_t j(0); j<a.m_transitions[i].size(); j++) {
1367 os << i <<
" -> " << a.m_transitions[i][j].nextState()
1369 << *(a.m_transitions[i][j].transitionUnit())
1383 for (uint64_t i(0); i<a.numberOfStates(); i++) {
1384 if (a.isFinalState(i)) { os << i <<
" [final]" <<
QTENDL; }
1385 for (uint64_t j(0); j<a.m_transitions[i].size(); j++) {
1386 os << i <<
" -> " << a.m_transitions[i][j].nextState()
1388 << *(a.m_transitions[i][j].transitionUnit())
#define LIMA_AUTOMATON_EXPORT
#define LIMA_EXCEPTION(X)
This macro writes the message X to a previously configured error stream before throwing a LimaExcepti...
QDebug & operator<<(QDebug &qd, const std::string &str)
LinguisticGraph::vertex_descriptor LinguisticGraphVertex
#define DEFAULT_MAXRESULTSIZE
#define DEFAULT_MAXDEPTHSTACK
#define DEFAULT_MAXNBRESULTS
#define DEFAULT_MAXTRANSITIONSEXPLORED
Holds all data that pass through the ProcessUnits Analysis data are shared pointers,...
Provide function to read write and check a property.
␈rief a class for control parameters for the search using the automata
uint64_t getMaxTransitionsExplored() const
uint64_t getMaxResultSize() const
uint64_t getMaxDepthStack() const
~AutomatonControlParams()
uint64_t getMaxNbResults() const
bool operator()(const AutomatonMatch &r1, const AutomatonMatch &r2) const
bool isLimitVertex(const LinguisticGraphVertex &v) const
bool push(const LinguisticGraphVertex &vertex, const Tstate &state, AnalysisContent &analysis, const LinguisticGraphVertex &limit)
DFSStack(const Automaton &a, const LinguisticAnalysisStructure::AnalysisGraph &graph, SearchGraph *searchGraph, const LinguisticGraphVertex &limit)
bool isEndVertex(const LinguisticGraphVertex &v) const
␈rief A class for the description of automata
void makeFinal(const Tstate state)
make a state final
Automaton reverse() const
build the automaton that will accept the reverse strings of the language (does not change the current...
void removeState(const Tstate state)
bool m_deterministic
a boolean flag indicating if the automaton is deterministic or not
Automaton & operator=(const Automaton &a)
assignment operator
Tstate addState(bool is_final=false)
add a state to the automaton
std::pair< RecognizerMatch, ConstraintCheckList > AutomatonMatch
types defined to store the result (or results of the application of the automaton on a graph
bool hasTransitionsState(const Tstate state) const
test if a state of the automaton has out transitions
void init()
profix of identifier of transition
bool getMatchingTransitions(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &vertex, AnalysisContent &analysis, const SearchGraph *searchGraph, const Tstate &state, std::vector< std::pair< std::deque< LinguisticGraphVertex >, const Transition * > > &matchingTransitions, const LinguisticGraphVertex &limit) const
bool existsEpsilonPathToFinal(const Tstate state) const
Automaton subsets() const
make deterministic automaton with the subsets method (does not change the current instance of the aut...
uint64_t numberOfTransitions() const
get the number of transitions in the automaton
bool getBestMatch(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &begin, const LinguisticGraphVertex &limit, AnalysisContent &analysis, RecognizerMatch &longestMatch, ConstraintCheckList &checkList, const SearchGraphSense sense, const AutomatonControlParams &controlParams) const
test if a text corresponds to the automaton : the text is represented as a LinguisticAnalysisStructur...
bool addTransition(Tstate initialState, Tstate finalState, TransitionUnit *transition)
add a transition between two states
bool getAllMatches(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &begin, const LinguisticGraphVertex &limit, AnalysisContent &analysis, AutomatonMatchSet &allMatches, ConstraintCheckList &checkList, ForwardSearch &forward, BackwardSearch &backward, const SearchGraphSense sense, const AutomatonControlParams &controlParams) const
get all matches found between automaton and graph between two points (WARNING: in case of backward se...
std::vector< bool > m_finalStates
which states are final states
Tstate numberOfStates() const
get the number of states of the automaton
void reinit()
reinitializes the automaton (no states, no transitions)
bool isFinalState(const Tstate state) const
test if a given state is a final state of the automaton
std::vector< TransitionUnit * > collectTransitions() const
void copy(const Automaton &a)
std::vector< std::vector< Transition > > m_transitions
the transitions
bool isFinalSubset(const SubSet &v) const
Tstate m_numberStates
number of states in the automaton
void reachableStates(const SubSet &states, const TransitionUnit &t, SubSet &reachable) const
std::set< Tstate > SubSet
bool testFromState(const Tstate firstState, const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &begin, const LinguisticGraphVertex &limit, AnalysisContent &analysis, AutomatonMatchSet &results, ConstraintCheckList &checkList, DFSStack &stack, const AutomatonControlParams &controlParams) const
std::string subsetString(const SubSet &subset) const
bool isDeterministic() const
test if the automaton is deterministic or not
friend LIMA_AUTOMATON_EXPORT std::ostream & operator<<(std::ostream &os, const Automaton &a)
output operator << overloading
std::vector< TransitionSearchStructure< Transition > * > m_searchStructures
void removeTransition(const Tstate initialState, const TransitionUnit &transition)
std::vector< Tstate > finalStates() const
get the list of the final states of the automaton
void unMakeFinal(const Tstate state)
remove a state from the final states
void setActionHash(const std::vector< std::pair< LimaString, Constraint > > &actionsWithOneArgument)
set a property hashcode to each transition which represent the constraint(s?) of type action attached...
void initializeSearchStructures(MediaId language)
Automaton brzozowskiMinimize() const
Brzozowski's algorithm for minimization : double reverse and determinization (does not change the cur...
std::set< AutomatonMatch, CompareAutomatonMatch > AutomatonMatchSet
void setDeterministic(const bool det)
set the flag indicating if the automaton is deterministic or not (does not make the automaton determi...
const LimaString & getComplementString()
void setHead(const LinguisticGraphVertex &v)
bool matchPath(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &vertex, const LinguisticGraphVertex &limit, const SearchGraph *searchGraph, AnalysisContent &analysis, const LinguisticAnalysisStructure::Token *token, std::deque< LinguisticGraphVertex > &vertices, const LinguisticAnalysisStructure::MorphoSyntacticData *) const
void addBackVertex(const LinguisticGraphVertex &, bool isKept=true, const LimaString &ruleElementId="")
uint64_t numberOfElements() const
virtual bool isEpsilonTransition() const
void setActionHash(const std::string &actionHash)
bool checkConstraints(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &vertex, AnalysisContent &analysis, ConstraintCheckList &) const
const std::string & getId() const
virtual TransitionUnit * clone() const =0
TransitionUnit * transitionUnit() const
An AnalysisData containing a LinguisticGraph with a language and an id.
const LinguisticGraph * getGraph(void) const
Returns the underlying graph structure.
Holds morphosyntactic informations.
holds surface data of a token
static const MediaticData & single()
const singleton accessor
SearchGraphSense
enumerated type to indicate in which sense the automaton should be built or searched
@ FORWARDSEARCH
forward search in the graph
@ BACKWARDSEARCH
backward search in the graph
std::vector< ConstraintCheckListElement > ConstraintCheckList
std::pair< std::deque< LinguisticGraphVertex >, const Transition * > DFFSPos