LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
automaton.cpp
Go to the documentation of this file.
1// Copyright 2002-2020 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6/************************************************************************
7*
8* File : automaton.cpp
9* Author : Romaric Besan�n (besanconr@zoe.cea.fr)
10* Created on : Fri Oct 04 2002
11* Copyright : (c) 2002 by CEA
12*
13************************************************************************/
14
15
16#include "automaton.h"
17#include "epsilonTransition.h"
19#include <boost/tuple/tuple.hpp> // for tie
20#include <iostream>
21#include <fstream>
22#include <algorithm>
23#include <vector>
24#include <stack>
25#include <utility>
26#include <QCryptographicHash>
27
28
29using namespace std;
31
32namespace Lima {
33namespace LinguisticProcessing {
34namespace Automaton {
35
36/***********************************************************************/
37// a class for control parameters for the search using the automata
38
39#define DEFAULT_MAXDEPTHSTACK 100
40#define DEFAULT_MAXTRANSITIONSEXPLORED 1000
41#define DEFAULT_MAXNBRESULTS 50
42#define DEFAULT_MAXRESULTSIZE 200
43
44// a structure to store the position of the search in the automaton
45typedef std::pair<std::deque<LinguisticGraphVertex>,const Transition*> DFFSPos;
46
48m_maxDepthStack(DEFAULT_MAXDEPTHSTACK),
49m_maxTransitionsExplored(DEFAULT_MAXTRANSITIONSEXPLORED),
50m_maxNbResults(DEFAULT_MAXNBRESULTS),
51m_maxResultSize(DEFAULT_MAXRESULTSIZE)
52{
53}
54
58
59/***********************************************************************/
60// constructors
61/***********************************************************************/
62Automaton::Automaton( const std::string& automId ):
63 m_numberStates(0),
64 m_finalStates(0),
65 m_transitions(0),
66 m_searchStructures(0),
67 m_deterministic(false),
68 m_id(automId)
69{
70}
71
73 m_numberStates(nbStates),
74 m_finalStates(nbStates,false),
75 m_transitions(nbStates),
76 m_searchStructures(nbStates,0),
77 m_deterministic(false),
78 m_id("")
79{
80}
81
83 init();
84 copy(a);
85}
86
87/***********************************************************************/
88// destructor
89/***********************************************************************/
93
94/***********************************************************************/
95// assignment operator
96/***********************************************************************/
98 if (this != &a) {
99 freeMem();
100 init();
101 copy(a);
102 }
103 return *this;
104}
105
106//**********************************************************************
107// helper functions for constructors and destructors
109{
111 m_finalStates.clear();
112 m_transitions.clear();
113 m_searchStructures.clear();
114 m_deterministic=false;
115}
116
118{
119 m_numberStates=a.numberOfStates();
120 m_finalStates=a.m_finalStates;
121 m_transitions=a.m_transitions;
122 m_deterministic=a.m_deterministic;
123
124 // clone search structures if necessary
125 m_searchStructures.clear();
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++) {
130 if ((*it)!=0) {
132 push_back(new TransitionSearchStructure<Transition>(**it));
133 }
134 else {
136 }
137 }
138}
139
141{
142 m_finalStates.clear();
143 m_transitions.clear();
144 std::vector<TransitionSearchStructure<Transition>*>::iterator
145 it=m_searchStructures.begin(),
146 it_end=m_searchStructures.end();
147 for (; it!=it_end;it++) {
148 if ((*it)!=0) {
149 delete (*it);
150 *it=0;
151 }
152 }
153 m_searchStructures.clear();
154}
155
158 freeMem();
159}
160
161/***********************************************************************/
162// access functions
163/***********************************************************************/
164
166 uint64_t nbTrans(0);
167 for (uint64_t i(0); i<m_numberStates; i++) {
168 nbTrans+=m_transitions[i].size();
169 }
170 return nbTrans;
171}
172
173vector<Tstate> Automaton::finalStates() const {
174 vector<Tstate> finals(0);
175 for (uint64_t i(0); i<m_numberStates; i++) {
176 if (m_finalStates[i]) {
177 finals.push_back(i);
178 }
179 }
180 return finals;
181}
182
183bool Automaton::hasTransitionsState(const Tstate state) const {
184 if (m_searchStructures[state]==0) {
185// AULOGINIT;
186// LDEBUG << "search structure not initialized";
187 return (! m_transitions[state].empty());
188 }
189 else {
190 return (! m_searchStructures[state]->empty());
191 }
192}
193
194/***********************************************************************/
195// to test the automaton
196/***********************************************************************/
197
198//***************************************************************************
199// indicates if it exists at least one path leading to a final state
200// that contains only epsilon transitions
202 Tstate currentState(state);
203 if (isFinalState(currentState)) { return true; }
204 for (uint64_t i(0); i<m_transitions[currentState].size(); i++) {
205 if (m_transitions[currentState][i].transitionUnit()->isEpsilonTransition()) {
206 if (existsEpsilonPathToFinal(m_transitions[currentState][i].nextState())) {
207 return true;
208 }
209 }
210 }
211 return false;
212}
213
215 std::cerr << "Automaton::initializeSearchStructure " << (void*)this << std::endl;
216 const Common::PropertyCode::PropertyAccessor* macro=&(static_cast<const Common::MediaticData::LanguageData&>(Common::MediaticData::MediaticData::single().mediaData(language)).getPropertyCodeManager().getPropertyAccessor("MACRO"));
217 const Common::PropertyCode::PropertyAccessor* micro=&(static_cast<const Common::MediaticData::LanguageData&>(Common::MediaticData::MediaticData::single().mediaData(language)).getPropertyCodeManager().getPropertyAccessor("MICRO"));
218 std::cerr << "Automaton::initializeSearchStructure macro " << (void*)macro << std::endl;
219 std::cerr << "Automaton::initializeSearchStructure micro " << (void*)micro << std::endl;
220 for (uint64_t i(0); i<m_numberStates; i++) {
221 if (m_searchStructures[i]==0) {
223 }
224 else {
225 m_searchStructures[i]->clear();
226 }
227 m_searchStructures[i]->init(m_transitions[i],macro,micro);
228 }
229 m_transitions.clear();
230}
231
234 const LinguisticGraphVertex& vertex,
235 AnalysisContent& analysis,
236 const SearchGraph* searchGraph,
237 const Tstate& state,
238 std::vector<DFFSPos>& matchingTransitions,
239 const LinguisticGraphVertex& limit
240 ) const {
241 Token* token = get(vertex_token, *(graph.getGraph()), vertex);
242 if (token == nullptr) {
243 AULOGINIT;
244 LIMA_EXCEPTION("Automaton::getMatchingTransitions no token for vertex " << vertex);
245 }
246 MorphoSyntacticData* data = get(vertex_data, *(graph.getGraph()), vertex);
247 if (data == nullptr) {
248 AULOGINIT;
249 LIMA_EXCEPTION("Automaton::getMatchingTransitions no morphosyntactic data for vertex " << vertex);
250 }
251
252#ifdef DEBUG_LP
253 AULOGINIT;
254// LDEBUG << "Automaton::getMatchingTransitions(vertex: " << vertex << ")";
255// LDEBUG << "search structure not initialized: linear search";
256#endif
257
258 if (m_searchStructures[state]==0) {
259 //linear search on the transitions
260
261#ifdef DEBUG_LP
262 //LDEBUG << "Automaton::getMatchingTransitions: search structure not initialized: linear search";
263#endif
264
265 matchingTransitions.clear();
266 vector<Transition>::const_iterator
267 trans=m_transitions[state].begin(),
268 trans_end=m_transitions[state].end();
269
270 for (; trans!=trans_end; trans++) {
271
272// #ifdef DEBUG_LP
273// LDEBUG << "Automaton::getMatchingTransitions vertex: " << vertex << " transition " << *trans;
274// #endif
275
276 deque<LinguisticGraphVertex> noVertices;
277 DFFSPos newPair(noVertices,nullptr);
278
279 bool match=(*trans).transitionUnit()->compare(graph,vertex,analysis,token,data);
280
281// #ifdef DEBUG_LP
282// LDEBUG << "Automaton::getMatchingTransitions compare result: " << (match ? "TRUE" : "FALSE");
283// #endif
284
285 const GazeteerTransition* gtrans = dynamic_cast<const GazeteerTransition*>((*trans).transitionUnit());
286 // TODO: generalize buildNextTermsList and checkMultiTerms to be able to manage backtrack and backward
287 if( gtrans != 0 ) {
288 deque<LinguisticGraphVertex> vertices;
289 match = gtrans->matchPath(graph, vertex, limit, searchGraph, analysis, token, vertices, data);
290 if( match ) {
291#ifdef DEBUG_LP
292 AULOGINIT;
293 ostringstream oss;
294 std::copy(vertices.begin(),vertices.end(),std::ostream_iterator<int>(oss,"-"));
295 LDEBUG << "GazeteerTransition returned a match with vertices " << oss.str();
296#endif
297 newPair = DFFSPos(vertices,&(*trans));
298 }
299 }
300 else {
301 deque<LinguisticGraphVertex> singleton(1,vertex);
302 newPair = DFFSPos(singleton,&(*trans));
303 }
304 if ((*trans).transitionUnit()->negative()) {
305 match = (!match);
306 }
307 if (match) {
308 matchingTransitions.push_back(newPair);
309 }
310 }
311#ifdef DEBUG_LP
312 LDEBUG << "Automaton::getMatchingTransitions: found" << matchingTransitions.size() << "matching transitions";
313#endif
314 return (!matchingTransitions.empty());
315 }
316 else {
317
318#ifdef DEBUG_LP
319 LDEBUG << "Automaton::getMatchingTransitions: search structure initialized find";
320#endif
321
322 return m_searchStructures[state]->
323 findMatchingTransitions2(graph,vertex,limit,searchGraph,analysis,token,data,matchingTransitions);
324 }
325}
326
327//**********************************************************************
328// main function: test the automaton on a morphological graph
329//***********************************************************************
330// comparison operator for elements of AutomatonMatchSet
332operator()(const AutomatonMatch& r1,
333 const AutomatonMatch& r2) const {
334 // operator > : first result is result with more coverage
335 const RecognizerMatch& m1=r1.first;
336 const RecognizerMatch& m2=r2.first;
337
338 // number of kept elements
339 uint64_t nbElt1=m1.numberOfElements();
340 uint64_t nbElt2=m2.numberOfElements();
341
342 if (nbElt1 > nbElt2) {
343 return true;
344 }
345 if (nbElt1 == nbElt2) {
346 // use size as second criteria
347 uint64_t size1=m1.size();
348 uint64_t size2=m2.size();
349 if (size1 > size2) {
350 return true;
351 }
352 else if (size1 == size2) {
353 // use vertex numbers as last criteria
354 // take greater vertex first (should be the last tested)
355 for (uint64_t i(0); i<size1; i++) {
356 if (m1[i].getVertex() > m2[i].getVertex()) {
357 return true;
358 }
359 if (m1[i].getVertex() < m2[i].getVertex()) {
360 return false;
361 }
362 }
363 }
364 }
365 return false;
366}
367
368// internal definition of a utility class:
369// stack for DFS test function
370
371std::ostream& operator<< (std::ostream& os, const DFFSPos& x) {
372 os << "[vertices=";
373 for (auto i = x.first.begin(); i != x.first.end(); i++) {
374 if (i != x.first.begin())
375 os << ",";
376 os << *i;
377 }
378 os << " transitions=";
379 if (x.second == NULL)
380 os << "NULL";
381 else
382 os << *(x.second);
383 os << "]";
384
385 return os;
386}
387
389public:
390 friend LIMA_AUTOMATON_EXPORT std::ostream& operator<< (std::ostream& os, const Automaton::DFSStack& x);
391
394 SearchGraph* searchGraph,
395 const LinguisticGraphVertex& limit):
396 m_stack(),
397 m_automaton(a),
398 m_graph(graph),
399 m_searchGraph(searchGraph),
400 m_limit(limit) {}
401
403
404 uint64_t size() const { return m_stack.size(); }
405 bool empty() const { return m_stack.empty(); }
407 { return (v==m_limit);}
408
410 { return (v==m_searchGraph->endOfGraph(m_graph)); }
411
412 // std::pair<LinguisticGraphVertex,const Transition*> top();
413 DFFSPos top();
414 /* TODO: usefull?
415 * void popVertex();
416 */
417 bool pop();
418 bool push(const LinguisticGraphVertex& vertex,
419 const Tstate& state,
420 AnalysisContent& analysis,
421 const LinguisticGraphVertex& limit);
422private:
423 struct DFSStackElement {
424 DFSStackElement( std::vector<DFFSPos>& matchingTransitions):
425 m_transitions(matchingTransitions),
426 m_transition(matchingTransitions.begin())
427 {
428 }
429
430 DFSStackElement(const DFSStackElement& elt):
431 m_transitions(elt.m_transitions),
432 m_transition(m_transitions.begin())
433 {
434 }
435
436 ~DFSStackElement() {}
437
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())
441 os << " ";
442 os << *i;
443 }
444 }
445
446 std::vector<DFFSPos > m_transitions;
447 //std::vector<std::pair<LinguisticGraphVertex, const Transition*> > m_transitions;
448 std::vector<DFFSPos>::const_iterator m_transition;
449 //std::vector<std::pair<LinguisticGraphVertex, const Transition*> >::const_iterator m_transition;
450 };
451 std::vector<DFSStackElement> m_stack;
452 const Automaton& m_automaton;
454 SearchGraph* m_searchGraph;
455 LinguisticGraphVertex m_limit;
456};
457
458
459std::ostream& operator<< (std::ostream& os, const Automaton::DFSStack& x) {
460 os << "m_stack = {\n";
461
462 for (auto i = x.m_stack.begin(); i != x.m_stack.end(); i++) {
463 if (i != x.m_stack.begin())
464 os << "\n";
465 i->debug_output(os);
466 }
467
468 os << "}\n";
469
470 return os;
471}
472
473QDebug& operator<< (QDebug& os, const Automaton::DFSStack& x) {
474 std::stringstream ss;
475 ss << x;
476 os << ss.str().c_str();
477 return os;
478}
479
480//std::pair<LinguisticGraphVertex,const Transition*>
482// AULOGINIT;
483// LDEBUG << "Automaton:DFSSTack: top "
484// << "transition=" << *(m_stack.back().m_transition)
485// << ";transitionUnit="
486// << (*(m_stack.back().m_transition))->transitionUnit()
487// ;
488 return *(m_stack.back().m_transition);
489}
490
492// #ifdef DEBUG_LP
493// AULOGINIT;
494// LDEBUG << "Automaton:DFSSTack: poping ";
495// #endif
496 m_stack.back().m_transition++;
497 if (m_stack.back().m_transition==
498 m_stack.back().m_transitions.end()) {
499// LDEBUG << "Automaton:DFSSTack: end of transitions: poping vertex "
500// ;
501 m_stack.pop_back();
502 return true;
503 }
504 return false;
505}
506
507/* TODO usefull?
508 * void Automaton::DFSStack::popVertex() {
509 m_stack.pop_back();
510}
511*/
512/*
513 * fill the stack with pairs (nextV,matchingTransition)
514 * nextV is one of the successor nodes in the graph
515 * The function look for possible transition from state
516 * and select matchingTransition = set of transition which succeed with nextV
517 */
518/*
519 * Pour remplir la pile, on itére sur les outVertex,
520 * puis pour chaque vertex, on regarde quelles transitions obtiennent un succès
521 * Cela ressemble à l'initialisation d'un mode largeur d'abord...
522 * En fait, c'est simplement pour limiter la taille de la structure de données qui gère le contexte de parcours.
523 * Le parcours se fait en profondeur d'abord (DFS Deep First Search)
524 * conforme au nom de la pile DFSStack.
525 *
526 * Le parcours se fait en profondeur d'abord sur le graphe d'analyse, limité sur plusieurs aspects:
527 * - les limites du graphe (begin, end), c'est à dire les noeuds 0 et 1 qui terminent le treillis.
528 * (si le parcours se fait en avant, limit = end, si le parcours se fait en arière, limit = begin)
529 * - la profondeur de la pile (pour éviter des traitements trop longs et des dépassements de pile sur
530 * des textes 'pathologiques', ex: des texts issus de tableaux)
531 * - le nombre de backtrack???
532 * L'unité d'avancement dans ce parcours est le passage d'un noeud à l'un des noeuds successeurs
533 * dans le graphe d'analyse. De même dans les opérations de backtrack, on revient sur une étape de
534 * ce parcours.
535 * Si on souhaite intégrer les transitions de type GazetteerTransition, il faut pouvoir
536 * gérer une unité d'avancement différente: il faut envisager l'avancement sur plusieurs noeuds
537 * successifs du graphe lorsqu'il y a un match d'un élément multi-terme du gazetteer. De même le
538 * backtrack doit se faire jusqu'au point d'avancement précédent donc revenir en arrière sur
539 * plusieurs noeuds.
540 * Une pile sert à gérer le point d'avancement dans le parcours.
541 * Actuellement, pour remplir la pile, on itére sur les 'out vertex' puis pour chaque vertex, on regarde
542 * quelles transitions obtiennent un succès. Cela ne convient plus car on ne couvre pas le cas des noeuds
543 * atteints par les éléments multi-termes des gazeteer.
544 * En effet, pour une paire (out vertex, transition) qui décrit une possibilité d'avancement, l'exécution de
545 * la transition va nous faire avancer au delà du noeud 'out vertex' dans le cas des multi-terme.
546 * Toutes les transitions ne font pas atteindre le même noeud.
547 * On est donc obligé de modifier la structure de données de la pile qui gére le contexte de parcours et le
548 * backtrack.
549 * Changement:
550
551 * On modifie seulement Automaton::getMatchingTransitions et la structure Automaton::DFSStack.
552 * On considère que nextVertex est la direction dans laquelle on va, mais la transition peut mener plus loin.
553 * On modifie DFSStackElement de la façon suivante:
554 * DFSStackElement contenait un noeud (out vertex) et une collection (vector) de transitions possibles
555 * DFSStackElement contient maintenant une collection (vector) de paires (séquence de noeud parcourus pendant la transition, transition possible)
556 * (stack<noeud>, transition), ainsi qu'un itérateur sur cette liste.
557 * stack<noeud> est le chemin dans le graphe (commençant par nextVertex) correspondant à l'exécution de la transition.
558 *
559 * Attention aux paramètres begin,end de la fonction checkMultiTerms
560 * La fonction checkMultiTerms a été écrite pour avec les limitations suivantes: sens forward seulement, pas de
561 * prise en compte de multiples arêtes à partir d'un noeud.
562 *
563 */
565push(const LinguisticGraphVertex& vertex,
566 const Tstate& state,
567 AnalysisContent& analysis,
568 const LinguisticGraphVertex& limit) {
569
570#ifdef DEBUG_LP
571 AULOGINIT;
572 LDEBUG << "Automaton:DFSSTack: pushing " << vertex << ";" << state;
573#endif
574
575 if (isLimitVertex(vertex)) {
576 return false;
577 }
578
579 if (! m_automaton.hasTransitionsState(state)) {
580 return false;
581 }
582
583 // use temporary stack to reverse elements
584 // (not efficient but to test similariry with previous version)
585 std::vector<DFSStackElement> tmpStack;
586
587 // look at next vertices (defined by the searchGraph strategy)
588 m_searchGraph->findNextVertices(m_graph.getGraph(),vertex);
589 LinguisticGraphVertex nextVertex;
590
591 while (m_searchGraph->getNextVertex(m_graph.getGraph(),nextVertex)) {
592
593// #ifdef DEBUG_LP
594// LDEBUG << "SearchGraph (inside while):";
595// ostringstream oss;
596// output(oss, m_searchGraph, m_graph.getGraph());
597// LDEBUG << oss.str();
598// #endif
599
600 if (! isEndVertex(nextVertex)) {
601
602 std::vector<DFFSPos> matchingTransitions(0);
603
604#ifdef DEBUG_LP
605 LDEBUG << "Automaton:get matching transitions from state "
606 << state << " for vertex " << nextVertex;
607#endif
608
609 if (m_automaton.
610 getMatchingTransitions(m_graph,nextVertex,analysis,
611 m_searchGraph,state,matchingTransitions,limit)) {
612
613// #ifdef DEBUG_LP
614// if (logger.isDebugEnabled()) {
615// ostringstream oss;
616// std::vector<DFFSPos>::const_iterator
617// it=matchingTransitions.begin(),
618// it_end=matchingTransitions.end();
619// oss << "Automaton:DFSSTack: matching transitions = ";
620// for (;it!=it_end;it++) {
621// oss << *it << ";";
622// }
623// LDEBUG << oss.str();
624// }
625// #endif
626
627 tmpStack.push_back(DFSStackElement(matchingTransitions));
628 }
629// #ifdef DEBUG_LP
630// else {
631// LDEBUG << "Automaton:DFSSTack: => no matching transitions";
632// }
633// #endif
634 }
635
636 }
637 // clear search structure for this vertex
638 m_searchGraph->clear();
639
640 if (tmpStack.empty()) {
641 return false;
642 } else {
643 m_stack.insert(m_stack.end(),tmpStack.rbegin(),tmpStack.rend());
644 }
645 // reverse stacked elements
646// while (!tmpStack.empty()) {
647// m_stack.push_back(tmpStack.top());
648// tmpStack.pop();
649// }
650
651 return true;
652}
653
654
657 const LinguisticGraphVertex& begin,
658 const LinguisticGraphVertex& limit,
659 AnalysisContent& analysis,
660 RecognizerMatch& longestMatch,
661 ConstraintCheckList& checkList,
662 const SearchGraphSense sense,
663 const AutomatonControlParams& controlParams) const {
664// AULOGINIT;
665// LDEBUG << "testing automaton from " << begin << " to " << limit;
666
667
668 AutomatonMatchSet results;
669 ForwardSearch forward;
670 BackwardSearch backward;
671 bool success=getAllMatches(graph,begin,limit,analysis,
672 results,checkList,forward,
673 backward,sense,controlParams);
674 if (success) {
675 // results are sorted so that first is best
676 success = false;
677 for ( auto & res : results ) {
678 if (res.first.hasDuplicateElements()) {
679 // As far as I understand duplicated elements in matching
680 // result are a sign of the bug in the matching engine
681 // TODO: fix matching engine or remove this workaround
682 AULOGINIT;
683 LERROR << "duplicate elements in RecognizerMatch:"
684 << res.first.getString();
685
686 continue;
687 }
688
689 longestMatch=res.first;
690 checkList=res.second;
691 success = true;
692 break;
693 }
694 if (! success)
695 return false;
696 if (sense == BACKWARDSEARCH) {
697 // reverse found match
698 std::reverse(longestMatch.begin(),longestMatch.end());
699 }
700 }
701
702// LDEBUG << "return success=" << success
703// << ",match=" << longestMatch;
704
705 return success;
706}
707
710 const LinguisticGraphVertex& begin,
711 const LinguisticGraphVertex& limit,
712 AnalysisContent& analysis,
713 AutomatonMatchSet& results,
714 ConstraintCheckList& checkList,
715 ForwardSearch& forward,
716 BackwardSearch& backward,
717 const SearchGraphSense sense,
718 const AutomatonControlParams& controlParams) const {
719
720 Tstate initialState(0);
721 bool success(false);
722
723 switch(sense) {
724 case FORWARDSEARCH: {
725 //SearchGraph* searchGraph=new ForwardSearch();
726 forward.reinit();
727 DFSStack forwardSearchStack(*this,graph,
728 &forward,
729 limit);
730 success = testFromState(initialState, graph,
731 begin, limit, analysis,
732 results,
733 checkList,
734 forwardSearchStack,
735 controlParams);
736 //delete searchGraph;
737 break;
738 }
739 case BACKWARDSEARCH: {
740 //SearchGraph* searchGraph=new BackwardSearch();
741 backward.reinit();
742 DFSStack backwardSearchStack(*this,graph,
743 &backward,
744 limit);
745 success = testFromState(initialState, graph,
746 begin, limit, analysis,
747 results,
748 checkList,
749 backwardSearchStack,
750 controlParams);
751 //delete searchGraph;
752 break;
753 }
754 }
755
756 return success;
757}
758
759bool Automaton::testFromState(const Tstate firstState,
761 const LinguisticGraphVertex& beginVertex,
762 const LinguisticGraphVertex& limitVertex,
763 AnalysisContent& analysis,
764 AutomatonMatchSet& results,
765 ConstraintCheckList& checkList,
766 DFSStack& S,
767 const AutomatonControlParams& controlParams) const {
768#ifdef DEBUG_LP
769 AULOGINIT;
770 LDEBUG << "Automaton: testing from state " << firstState;
771#endif
772
773 // store in stack pairs of (automaton transition/graph vertex)
774 // (store combinatory of all possible pairs, but if store only
775 // matching pairs, problems with ConstraintCheckList
776
777 RecognizerMatch currentMatch(&graph);
778
779 // check initial state
780 if (isFinalState(firstState)) {
781 results.insert(make_pair(currentMatch,checkList));
782 }
783
784 if (S.isEndVertex(beginVertex)) {
785// #ifdef DEBUG_LP
786// LDEBUG << beginVertex << "is end vertex. testing returns " << !results.empty();
787// #endif
788 return (!results.empty());
789 }
790
791 // beginVertex is the vertex that matched the trigger
792 // initialize the stack with pairs (stack of vertex with nextV as first element,matchingTransition)
793 // nextV is one of the successor nodes in the graph and matchingTransition(nextV) succeeds
794
795// #ifdef DEBUG_LP
796// LDEBUG << "pushing";
797// #endif
798 S.push(beginVertex,firstState,analysis,limitVertex);
799
801 const Transition* transition(nullptr);
802 uint64_t nbIter(0);
803 bool backtrack(false);
804
805 // contexte de backtrack
806 vector<uint64_t> backtrackDepth;
807 backtrackDepth.push_back(0);
808
809// #ifdef DEBUG_LP
810// LDEBUG << "before while (S size: " << S.size() << ")";
811// LDEBUG << "S: " << S;
812// #endif
813
814 while (! S.empty()) {
815 nbIter++;
816
817// #ifdef DEBUG_LP
818// LDEBUG << "in iteration " << nbIter << ":";
819// LDEBUG << " currentMatch =" << currentMatch;
820// LDEBUG << " stack =" << S;
821// ostringstream oss;
822// std::copy(backtrackDepth.begin(),backtrackDepth.end(),std::ostream_iterator<int>(oss," "));
823// LDEBUG << " backtrackDepth =" << oss.str();
824// #endif
825
826 if (S.size() > controlParams.getMaxDepthStack()) {
827 AULOGINIT;
828 LWARN << "MaxDepthStack exceeded in automaton search: ignore rest of search";
829 return (!results.empty());
830 }
831 if (nbIter > controlParams.getMaxTransitionsExplored()) {
832 AULOGINIT;
833 LWARN << "MaxTransitionsExplored exceeded in automaton search: ignore rest of search";
834 return (!results.empty());
835 }
836
837 // boost::tie(vertex,transition)=S.top();
838 DFFSPos const & dffsPos = S.top();
839 vertex = dffsPos.first.front();
840 transition = dffsPos.second;
841 if (backtrack) {
842 // in backtrack : pop_back current match until the vertex
843 // for which we are testing a new matching transition
844
845 if (backtrackDepth.empty()) {
846 AULOGINIT;
847 LWARN << "Automaton: should not be here! "
848 << "backtrack stack empty: abort search";
849 return (!results.empty());
850 }
851
852 uint64_t depth=backtrackDepth.back();
853
854// #ifdef DEBUG_LP
855// LDEBUG << "Automaton: backtrack: currentMatch="
856// << currentMatch << ", next matching for vertex "
857// << vertex << ", backtrack depth=" << depth;
858// #endif
859
860 if (currentMatch.size() < depth) {
861 AULOGINIT;
862 LWARN << "Automaton: should not be here! "
863 << "backtrack depth larger than current match size: abort search";
864 return (!results.empty());
865 }
866 for (uint64_t i(0); i<depth; i++) {
867 currentMatch.popBackVertex();
868 }
869 backtrackDepth.pop_back();
870 if (backtrackDepth.empty()) { // came back to start point
871 backtrackDepth.push_back(0);
872 }
873 backtrack=false;
874
875// #ifdef DEBUG_LP
876// LDEBUG << "currentMatch after backtrack = " << currentMatch;
877// #endif
878 }
879
880 bool lastTransitionWithThisVertex=S.pop();
881
882 // compare transition with vertex
883 TransitionUnit* trans=transition->transitionUnit();
884
885#ifdef DEBUG_LP
886 LDEBUG << "Automaton: testing vertex " << vertex << " with transition " << *trans;
887// if (lastTransitionWithThisVertex)
888// LDEBUG << "=> is last transition for vertex " << vertex << " depth == " << backtrackDepth.back();
889#endif
890
891 //if (trans->match(graph,vertex,analysis,checkList)) {
892 // TODO: call checkConstraints for every vertex in the deque?
893 if (trans->checkConstraints(graph,vertex,analysis,checkList)) {
894
895#ifdef DEBUG_LP
896 LDEBUG << "Automaton: -> match found";
897#endif
898 // update current match
899 LimaString transId = LimaString::fromUtf8( trans->getId().c_str() );
900 // OME: call for the complete stack currentMatch.addBackVertex(vertex,trans->keep(), transId);
901 std::deque<LinguisticGraphVertex>::const_iterator vIt = dffsPos.first.begin();
902 for( ; vIt != dffsPos.first.end() ; vIt++ ) {
903 currentMatch.addBackVertex(*vIt,trans->keep(), transId);
904 }
905
906 // test if it is the head
907 if (trans->head()) {
908 // get token associated to next vertex
909 currentMatch.setHead(vertex);
910 }
911
912 if (! lastTransitionWithThisVertex) {
913 // not the last transition to test for this vertex
914 // will have to come back to this branching point
915 // take size of multi-terms matching into account for backtrack depth (from GazeteerTransition)
916 backtrackDepth.push_back(dffsPos.first.size());
917 }
918 else {
919 backtrackDepth.back()+=dffsPos.first.size();
920 }
921
922 Tstate nextState=transition->nextState();
923 if (isFinalState(nextState)) {
924
925// #ifdef DEBUG_LP
926// LDEBUG << "Automaton: saving result of size "<< currentMatch.size();
927// #endif
928
929 if (currentMatch.size() > controlParams.getMaxResultSize()) {
930 AULOGINIT;
931 LWARN << "maxResultSize exceeded in automaton search: ignore result";
932 }
933 else {
934#ifdef DEBUG_LP
935 LDEBUG << "Automaton: add possible match: " << currentMatch;
936#endif
937 results.insert(make_pair(currentMatch,checkList));
938 if (results.size() > controlParams.getMaxNbResults()) {
939 AULOGINIT;
940 LWARN << "maxNbResults exceeded in automaton search: ignore rest of search";
941 return (!results.empty());
942 }
943 }
944
945/* if (logger.isDebugEnabled()) {
946 ostringstream oss;
947 AutomatonMatchSet::const_iterator
948 it=results.begin(),
949 it_end=results.end();
950 for (;it!=it_end;it++) {
951 oss << (*it).first << ";";
952 }
953 LDEBUG << "results are (" << oss.str() << ")";
954 }*/
955 if (lastTransitionWithThisVertex && ! hasTransitionsState(nextState)) {
956 backtrack=true;
957 }
958 }
959
960 // push next vertices
961 //if (!S.push(vertex,nextState,analysis,limitVertex)) {
962 if (!S.push(dffsPos.first.back(),nextState,analysis,limitVertex)) {
963// #ifdef DEBUG_LP
964// stringstream ss;
965// for (auto it = backtrackDepth.begin(); it != backtrackDepth.end(); it++)
966// ss << *it << " ";
967// LDEBUG << "backtrackDepth = [" << ss.str() << "]";
968// #endif
969
970 backtrack=true;
971 }
972 }
973 else if (lastTransitionWithThisVertex) {
974 backtrack=true;
975 }
976 }
977
978 return (!results.empty());
979}
980
981/***********************************************************************/
982// to build the automaton
983/***********************************************************************/
986 m_finalStates.push_back(is_final);
987 m_transitions.push_back(vector<Transition>());
989 return m_numberStates-1; // first state is 0
990}
991
992// copy the content of the pointer (insert function of the
994 Tstate finalState,
995 TransitionUnit* transition) {
996
997 vector<Transition>& transitions=m_transitions[initialState];
998
999 // put negative transition at the end, so that positive transitions
1000 // are tested before : if not(a) and (b) are possible transitions,
1001 // token "b" matches both, so transition (b) has to be checked before
1002 // this way, we can advance in the automaton
1003 // being sure that we do not need to go back eventually
1004 if (transition->negative()) {
1005 transitions.push_back(Transition(transition,finalState));
1006 }
1007 else { // put int front
1008 // putting epsilon transitions at first helps minimizing automaton
1009 vector<Transition>::iterator
1010 it=transitions.begin(),
1011 it_end=transitions.end();
1012 for (; it!=it_end; it++) {
1013 if (!(*it).transitionUnit()->isEpsilonTransition()) {
1014 break;
1015 }
1016 }
1017 transitions.insert(it,Transition(transition,finalState));
1018#ifdef DEBUG_LP
1019 AULOGINIT;
1020 it=transitions.begin(),
1021 it_end=transitions.end();
1022 for (; it!=it_end; it++) {
1023 if (!(*it).transitionUnit()->isEpsilonTransition()) {
1024 break;
1025 }
1026 }
1027 LDEBUG << "Automaton::addTransition( " << (*it).transitionUnit() << ")";
1028#endif
1029
1030
1031// transitions.insert(transitions.begin(),Transition(transition,finalState));
1032 }
1033
1034// std::cerr << Common::Misc::utf8stdstring2limastring("add transition ")
1035// << *transition << Common::Misc::utf8stdstring2limastring(" from ") << initialState
1036// << Common::Misc::utf8stdstring2limastring(" to ") << finalState << endl;
1037 return true;
1038}
1039
1041 // on est oblige de tout renumeroter...
1042 std::cerr << "Warning: removeState not yet implemented..." << endl;
1043}
1044
1045void Automaton::removeTransition(const Tstate initialState,
1046 const TransitionUnit& transition) {
1047 vector<Transition>::iterator i;
1048 for (i=m_transitions[initialState].begin(); i<m_transitions[initialState].end(); i++) {
1049 if (*(i->transitionUnit()) == transition) {
1050 m_transitions[initialState].erase(i);
1051 return;
1052 }
1053 }
1054}
1055
1056void Automaton::makeFinal(const Tstate state) {
1057 m_finalStates[state]=true;
1058}
1059
1061 m_finalStates[state]=false;
1062}
1063
1065 m_deterministic=val;
1066}
1067
1068/***********************************************************************/
1069// makes a deterministic automaton from a non-deterministic one
1070// using a simple subset construction
1071/***********************************************************************/
1072// some operations on SubSets (could be in a separate class)
1073std::string Automaton::subsetString(const Automaton::SubSet& subset) const {
1074 ostringstream oss;
1075 oss << "[";
1076 if (!subset.empty()) {
1077 SubSet::const_iterator
1078 state=subset.begin(),
1079 state_end=subset.end();
1080 oss << *state;
1081 state++;
1082 for (; state!=state_end; state++) {
1083 oss << "," << *state;
1084 }
1085 }
1086 oss << "]";
1087 return oss.str();
1088}
1089
1090// bool operator== (const vector<Tstate>& v1, const vector<Tstate>& v2) {
1091// if (v1.size() != v2.size()) { return false; }
1092// for (uint64_t i(0); i<v1.size(); i++) {
1093// if (v1[i] != v2[i]) { return false; }
1094// }
1095// return true;
1096// }
1097
1098// test if a set of states contains at least one final state
1099bool Automaton::isFinalSubset (const SubSet& v) const {
1100 SubSet::const_iterator
1101 state=v.begin(),
1102 state_end=v.end();
1103 for (; state!=state_end; state++) {
1104 if (isFinalState(*state)) {
1105 return true;
1106 }
1107 }
1108 return false;
1109}
1110
1112 vector<TransitionUnit*> alphabet;
1113 vector< Automaton::SubSet > subsets;
1114 Automaton::SubSet currentSubset;
1115 Automaton detFA;
1116
1117 alphabet=collectTransitions();
1118#ifdef DEBUG_LP
1119 AULOGINIT;
1120 LDEBUG << "Automaton::subsets():\n";
1121 ostringstream oss;
1122 oss << "alphabet=";
1123 for (uint64_t i(0); i<alphabet.size(); i++) {
1124 oss << *(alphabet[i]) << "\n";
1125 }
1126 LDEBUG << oss.str();
1127#endif
1128
1129 detFA.addState();
1130 //initial state is possibly final
1131 if ((! isDeterministic()) &&
1133 detFA.makeFinal(0);
1134 }
1135
1136 SubSet firstSubSet;
1137 firstSubSet.insert(0);
1138 subsets.push_back(firstSubSet);
1139
1140 for (uint64_t i(0); i<detFA.numberOfStates(); i++) {
1141 for (uint64_t j(0); j<alphabet.size(); j++) {
1142 currentSubset.clear();
1143 reachableStates(subsets[i],*(alphabet[j]),currentSubset);
1144// LDEBUG << "reachables from " << subsetString(subsets[i])
1145// << " with " << *(alphabet[j]) << ":"
1146// << subsetString(currentSubset);
1147
1148 if (currentSubset.size()) {
1149 // if a subset already corresponds to the current subset
1150 // do not add state, just add transition
1151 bool existingSubset(false);
1152 for (uint64_t k(0); k<subsets.size(); k++) {
1153 if (currentSubset == subsets[k]) {
1154 TransitionUnit *t =(*(alphabet[j])).clone();
1155 //TransitionUnit *t =alphabet[j];
1156 detFA.addTransition(i,k,t);
1157 existingSubset=true;
1158// LDEBUG << "adding transition [" << i << "+"
1159// << *(alphabet[j]) << "->" << k << "]";
1160 break;
1161 }
1162 }
1163 if (! existingSubset) { // add the state
1164 Tstate lastState=detFA.addState();
1165 if (isFinalSubset(currentSubset)) { detFA.makeFinal(lastState); }
1166 subsets.push_back(currentSubset);
1167 TransitionUnit *t =(*(alphabet[j])).clone();
1168 //TransitionUnit *t =alphabet[j];
1169 detFA.addTransition(i,lastState,t);
1170// LDEBUG << "adding new state " << lastState
1171// << " and transition [" << i << "+"
1172// << *(alphabet[j]) << "->" << lastState << "]";
1173 }
1174 }
1175 }
1176 }
1177
1178 // clear alphabet
1179 for (uint64_t i(0); i< alphabet.size(); i++) {
1180 delete alphabet[i];
1181 alphabet[i]=0;
1182 }
1183 alphabet.clear();
1184
1185 detFA.setDeterministic(true);
1186 return detFA;
1187}
1188
1189
1190 void Automaton::setActionHash(const std::vector<std::pair<LimaString,Constraint> >& actionsWithOneArgument){
1191 // Enumerate all transitions of automate
1192 for (uint64_t i(0); i<m_numberStates; i++) {
1193 for (uint64_t j(0); j<m_transitions[i].size(); j++) {
1194 TransitionUnit& t = *(m_transitions[i][j].transitionUnit());
1195 if (t.isEpsilonTransition()) { continue; }
1196 // Enumerate all constraints of type action
1197 std::vector<std::pair<LimaString,Constraint> >::const_iterator constraintIt = actionsWithOneArgument.begin();
1198 #ifdef DEBUG_LP
1199 AULOGINIT;
1200 LDEBUG << "Automaton::setActionHash: compute hash for " << t;
1201#endif
1202 for( ; constraintIt != actionsWithOneArgument.end() ; constraintIt++ ) {
1203 // if id of transition and first argument of constraint have same value
1204 // means there is an action triggered by this transition
1205 std::string elementId = (constraintIt->first).toStdString();
1206 #ifdef DEBUG_LP
1207 LDEBUG << "Automaton::setActionHash: compare to " << elementId;
1208#endif
1209 if( !(elementId.compare(t.getId())) )
1210 {
1211 // build a hash with the name of the constraint and complement (second argument)
1212 // like SetEntityFeature(hour::int)
1213 // TODO: do not know how to get the name of the constraint
1214 ConstraintFunction* constraintFunc = (constraintIt->second).functionAddr();
1215 const LimaString complement = constraintFunc->getComplementString();
1216 LimaString signature = complement;
1217 QCryptographicHash hashFunctor(QCryptographicHash::Md5);
1218 hashFunctor.addData(signature.toUtf8());
1219 QString hashValue = QString(hashFunctor.result());
1220 // put this hash as identifier of action triggered by the transition
1221 t.setActionHash(hashValue.toStdString());
1222 #ifdef DEBUG_LP
1223 LDEBUG << "Automaton::setActionHash: set hash to " << hashValue;
1224#endif
1225 }
1226 }
1227 }
1228 }
1229}
1230
1231// get all the transitions that appear in the automaton
1232vector<TransitionUnit*> Automaton::collectTransitions() const {
1233 vector<TransitionUnit*> alphabet(0);
1234 bool alreadyCollected;
1235
1236 for (uint64_t i(0); i<m_numberStates; i++) {
1237 for (uint64_t j(0); j<m_transitions[i].size(); j++) {
1238 if (m_transitions[i][j].transitionUnit()->isEpsilonTransition()) { continue; }
1239 // tests if it is already collected
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;
1244 break;
1245 }
1246 }
1247 if (! alreadyCollected) {
1248 TransitionUnit *t=(*(m_transitions[i][j].transitionUnit())).clone();
1249 alphabet.push_back(t);
1250 }
1251 }
1252 }
1253 return alphabet;
1254}
1255
1256// get all the states that can be reached from a set of states with one
1257// particular transition
1259 const TransitionUnit& t,
1260 SubSet& reachable) const {
1261 SubSet::const_iterator
1262 state=states.begin(),
1263 state_end=states.end();
1264
1265 for (; state!=state_end; state++) {
1266 reachableStates(*state,t,reachable);
1267 }
1268}
1269
1271 const TransitionUnit& t,
1272 SubSet& reachable) const {
1273
1274 std::vector<Transition>::const_iterator
1275 transition=m_transitions[state].begin(),
1276 transition_end=m_transitions[state].end();
1277
1278 //for (uint64_t l(0); l<m_transitions[*state].size(); l++) {
1279 for (; transition!=transition_end; transition++) {
1280 Tstate nextState=transition->nextState();
1281 if (*(transition->transitionUnit()) == t) {
1282 reachable.insert(nextState);
1283 reachableStates(nextState, EpsilonTransition(), reachable);
1284 }
1285 else if (transition->transitionUnit()->isEpsilonTransition()) {
1286 reachableStates(nextState, t, reachable);
1287 }
1288 }
1289}
1290
1291/***********************************************************************/
1292// build the reverse automaton
1293/***********************************************************************/
1295 Automaton reverseAutomaton(numberOfStates()+1); // one more state (see below)
1296 Tstate newValueInitialState;
1297
1298 // the reverse automaton will not be deterministic (because in the
1299 // first deterministic automaton, several identical transitions can
1300 // lead to one state), hence we do not try to be subtle and always
1301 // add epsilon transitions for the new initial state (even if there
1302 // is only one final state in the original automaton)
1303
1304 // the initial state becomes the last state of the reverse automaton
1305 newValueInitialState=numberOfStates();
1306 reverseAutomaton.makeFinal(newValueInitialState);
1307
1308 vector<Tstate> finals(finalStates());
1309 // add one initial state and epsilon transitions
1310 for (uint64_t i(0); i<finals.size(); i++) {
1311 if (finals[i]==0) { // the initial state was also final
1312 reverseAutomaton.addTransition(0,newValueInitialState,new EpsilonTransition());
1313 }
1314 else {
1315 reverseAutomaton.addTransition(0,finals[i],new EpsilonTransition());
1316 }
1317 }
1318
1319 for (uint64_t i(0); i<m_transitions.size(); i++) {
1320 for (uint64_t j(0); j<m_transitions[i].size(); j++) {
1321 Tstate initial = m_transitions[i][j].nextState();
1322 Tstate final = i;
1323 if (initial == 0) { initial = newValueInitialState; }
1324 if (final == 0) { final = newValueInitialState; }
1325 reverseAutomaton.addTransition(initial, final,
1326 //m_transitions[i][j].transitionUnit());
1327 m_transitions[i][j].transitionUnit()->clone());
1328 }
1329 }
1330
1331 if (isDeterministic()) { // make the new one deterministic also
1332 reverseAutomaton = reverseAutomaton.subsets();
1333 }
1334
1335 return reverseAutomaton;
1336}
1337
1338/***********************************************************************/
1339// simple Brzozowski's algorithm for minimization : just reverse
1340// and determinize twice
1341/***********************************************************************/
1343 Automaton a;
1344 if (! isDeterministic()) {
1345 a=subsets();
1346 }
1347 else {
1348 a=*this;
1349 }
1350 a=a.reverse(); // determinization is done in function reverse if
1351 a=a.reverse(); // the automaton was already deterministic
1352 return a;
1353}
1354
1355/***********************************************************************/
1356// output
1357/***********************************************************************/
1358
1359
1360ostream& operator << (ostream& os, const Automaton& a) {
1361
1362 // os << "deterministic=" << a.isDeterministic() << endl;
1363
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()
1368 << "["
1369 << *(a.m_transitions[i][j].transitionUnit())
1370 << "]" << endl;
1371 }
1372 }
1373
1374 //os << "}" << endl;
1375
1376 return os;
1377}
1378
1379QDebug& operator << (QDebug& os, const Automaton& a) {
1380
1381 // os << "deterministic=" << a.isDeterministic() << endl;
1382
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()
1387 << " ["
1388 << *(a.m_transitions[i][j].transitionUnit())
1389 << "]" << QTENDL;
1390 }
1391 }
1392
1393 //os << "}" << endl;
1394
1395 return os;
1396}
1397
1398} // namespace end
1399} // namespace end
1400} // namespace end
#define LIMA_AUTOMATON_EXPORT
#define LWARN
Definition LimaCommon.h:160
#define QTENDL
Definition LimaCommon.h:32
#define LIMA_EXCEPTION(X)
This macro writes the message X to a previously configured error stream before throwing a LimaExcepti...
Definition LimaCommon.h:293
QDebug & operator<<(QDebug &qd, const std::string &str)
Definition QsLog.cpp:39
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
@ vertex_token
LinguisticGraph::vertex_descriptor LinguisticGraphVertex
@ vertex_data
#define AULOGINIT
#define DEFAULT_MAXRESULTSIZE
Definition automaton.cpp:42
#define DEFAULT_MAXDEPTHSTACK
Definition automaton.cpp:39
#define DEFAULT_MAXNBRESULTS
Definition automaton.cpp:41
#define DEFAULT_MAXTRANSITIONSEXPLORED
Definition automaton.cpp:40
Holds all data that pass through the ProcessUnits Analysis data are shared pointers,...
Holds linguistic data for one language.
const MediaData & mediaData(MediaId media) const
Provide function to read write and check a property.
␈rief a class for control parameters for the search using the automata
Definition automaton.h:44
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
Definition automaton.h:87
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...
bool m_deterministic
a boolean flag indicating if the automaton is deterministic or not
Definition automaton.h:346
Automaton & operator=(const Automaton &a)
assignment operator
Definition automaton.cpp:97
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
Definition automaton.h:196
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
Definition automaton.h:343
Tstate numberOfStates() const
get the number of states of the automaton
Definition automaton.h:390
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
Definition automaton.h:403
std::vector< TransitionUnit * > collectTransitions() const
std::vector< std::vector< Transition > > m_transitions
the transitions
Definition automaton.h:344
Tstate m_numberStates
number of states in the automaton
Definition automaton.h:342
void reachableStates(const SubSet &states, const TransitionUnit &t, SubSet &reachable) const
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
Definition automaton.h:409
friend LIMA_AUTOMATON_EXPORT std::ostream & operator<<(std::ostream &os, const Automaton &a)
output operator << overloading
std::vector< TransitionSearchStructure< Transition > * > m_searchStructures
Definition automaton.h:345
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...
Automaton brzozowskiMinimize() const
Brzozowski's algorithm for minimization : double reverse and determinization (does not change the cur...
std::set< AutomatonMatch, CompareAutomatonMatch > AutomatonMatchSet
Definition automaton.h:203
void setDeterministic(const bool det)
set the flag indicating if the automaton is deterministic or not (does not make the automaton determi...
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="")
void setActionHash(const std::string &actionHash)
bool checkConstraints(const LinguisticAnalysisStructure::AnalysisGraph &graph, const LinguisticGraphVertex &vertex, AnalysisContent &analysis, ConstraintCheckList &) const
virtual TransitionUnit * clone() const =0
An AnalysisData containing a LinguisticGraph with a language and an id.
const LinguisticGraph * getGraph(void) const
Returns the underlying graph structure.
static const MediaticData & single()
const singleton accessor
Definition Singleton.h:51
SearchGraphSense
enumerated type to indicate in which sense the automaton should be built or searched
Definition searchGraph.h:35
@ FORWARDSEARCH
forward search in the graph
Definition searchGraph.h:36
@ BACKWARDSEARCH
backward search in the graph
Definition searchGraph.h:37
std::vector< ConstraintCheckListElement > ConstraintCheckList
std::pair< std::deque< LinguisticGraphVertex >, const Transition * > DFFSPos
Definition automaton.cpp:45
NAUTITIA.
QString LimaString
Definition LimaString.h:33
STL namespace.