LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
IdiomaticAlternativesConstraints.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 * Copyright (C) 2004-2020 by CEA LIST *
8 * *
9 ***************************************************************************/
19
20#include <queue>
21
22using namespace std;
23using namespace Lima::Common::MediaticData;
24using namespace Lima::Common::AnnotationGraphs;
29
30namespace Lima
31{
32
33namespace LinguisticProcessing
34{
35
36namespace MorphologicAnalysis
37{
38
39// factories for constraint functions defined in this file
42
43
45 MediaId language,
46 const LimaString& complement):
47 CreateAlternative(language,complement)
48{
49// MORPHOLOGINIT;
50// LDEBUG << "CreateIdiomaticAlternative constructor with complement: " << complement;
51
52}
53
54
55void CreateIdiomaticAlternative::removeEdges(
56 LinguisticGraph& graph,
57 const RecognizerMatch& match,
58 AnalysisContent& analysis) const
59{
60#ifdef DEBUG_LP
62 LDEBUG << "IdiomaticAlternatives: removing edges";
63#endif
64/* if (first == last)
65 {
66 LDEBUG << " first and last are equal => ignoring";
67 return;
68 }*/
69 auto recoData = std::dynamic_pointer_cast<RecognizerData>(analysis.getData("RecognizerData"));
70
71
72 std::set< LinguisticGraphVertex > matchVertices;
73 Automaton::RecognizerMatch::const_iterator matchIt, matchIt_end;
74
75 // noeuds eventuellement pendants a verifier
76 std::set< LinguisticGraphVertex > verticesToCheck;
77
78 matchIt = match.begin();
79 matchIt_end = match.end();
80 for (; matchIt != matchIt_end; matchIt++)
81 {
82 matchVertices.insert((*matchIt).m_elem.first);
83 }
84
85 matchIt = match.begin();
86 matchIt_end = match.end();
87 // parcours des noeuds du match
88 for (; matchIt != matchIt_end; matchIt++)
89 {
90 LinguisticGraphOutEdgeIt outIt, outIt_end;
91 boost::tie (outIt, outIt_end) = boost::out_edges((*matchIt).m_elem.first, graph);
92 // pour chaque arc sortant du noeud
93 for (; outIt != outIt_end; outIt++)
94 {
95 // l'arc n'est pas membre du match
96 if (matchVertices.find(target(*outIt, graph)) != matchVertices.end())
97 {
98 // on le stocke comme a supprimer
99 recoData->setEdgeToBeRemoved(analysis, *outIt);
100 // il va falloir verifier si le noeud cible de l'arc ne se retrouve pas pendant quand on aura supprime l'arc
101 verticesToCheck.insert(target(*outIt, graph));
102 }
103 }
104
105 LinguisticGraphInEdgeIt inIt, inIt_end;
106 boost::tie (inIt, inIt_end) = boost::in_edges((*matchIt).m_elem.first, graph);
107 // pour chaque arc entrant du noeud
108 for (; inIt != inIt_end; inIt++)
109 {
110 // l'arc n'est pas membre du match
111 if (matchVertices.find(source(*inIt, graph)) != matchVertices.end())
112 {
113 // on le stocke comme a supprimer
114 recoData->setEdgeToBeRemoved(analysis, *inIt);
115 // il va falloir verifier si le noeud source de l'arc ne se retrouve pas pendant quand on aura supprime l'arc
116 verticesToCheck.insert(source(*inIt, graph));
117 }
118 }
119 }
120 // suppression des arcs stockes comme a supprimer
121 recoData->removeEdges( analysis );
122
123 //verification des noeuds extremites des arcs supprimes
124 std::set< LinguisticGraphVertex >::const_iterator verticesToCheckIt, verticesToCheckIt_end;
125 verticesToCheckIt = verticesToCheck.begin();
126 verticesToCheckIt_end = verticesToCheck.end();
127 for (;verticesToCheckIt != verticesToCheckIt_end; verticesToCheckIt++)
128 {
129 recoData->clearUnreachableVertices(analysis, *verticesToCheckIt);
130 }
131
132}
133
134
136 AnalysisContent& analysis) const
137{
138#ifdef DEBUG_LP
140 LDEBUG << "CreateIdiomaticAlternative, match is " << result;
141 LDEBUG << " expression is " << (result.isContiguous()?"":"non") <<
142 " contiguous and" << (result.isContextual()?" non":"") << " absolute";
143#endif
144 if (result.empty()) return false;
145 const LinguisticAnalysisStructure::AnalysisGraph& graph = *(result.getGraph());
146 auto annotationData = std::dynamic_pointer_cast< AnnotationData >(analysis.getData("AnnotationData"));
147 if (annotationData->dumpFunction("IdiomExpr") == 0)
148 {
149 annotationData->dumpFunction("IdiomExpr", new DumpIdiomaticExpressionAnnotation());
150 }
151
152 auto recoData = std::dynamic_pointer_cast<RecognizerData>(analysis.getData("RecognizerData"));
153
154 std::set<LinguisticGraphVertex> addedVertices;
155 // initialize the vertices to clear
156
157 if (result.isContiguous())
158 {
159// MORPHOLOGINIT;
160// LDEBUG << "contiguous idiomatic expression found: "
161// << result.concatString();
162
163 // only one part : terms in expression are adjacent -> easy part
164
165 // check if there is an overlap first
166 if (recoData->matchOnRemovedVertices(result))
167 {
168 // ignore current idiomatic expression, continue
170 LWARN << "idiomatic expression ignored: " << Common::Misc::limastring2utf8stdstring(result.concatString())
171 << ": overlapping with a previous one";
172 return false;
173 }
174
175 // create the new token
176 std::pair<Token*,MorphoSyntacticData*> newToken = createAlternativeToken(result);
177 if (newToken.second->empty())
178 {
179 // ignore current idiomatic expression, continue
181 LERROR << "CreateIdiomaticAlternative::operator() Got empty morphosyntactic data. Abort";
182 delete newToken.first;
183 delete newToken.second;
184 return false;
185 }
186
187 // add the vertex
188 LinguisticGraphVertex idiomaticVertex =
189 addAlternativeVertex(newToken.first, newToken.second, const_cast<LinguisticGraph*>(graph.getGraph()));
190 AnnotationGraphVertex agv = annotationData->createAnnotationVertex();
191 annotationData->addMatching("AnalysisGraph", idiomaticVertex, "annot", agv);
192 annotationData->annotate(agv, Common::Misc::utf8stdstring2limastring("AnalysisGraph"), idiomaticVertex);
193 IdiomaticExpressionAnnotation annot(result);
194 GenericAnnotation ga(annot);
195 annotationData->annotate(agv, Common::Misc::utf8stdstring2limastring("IdiomExpr"), ga);
196
197 addedVertices.insert(idiomaticVertex);
198
199 //create the alternative with this only vertex
200 createBeginAlternative(result.front().getVertex(),
201 idiomaticVertex,const_cast<LinguisticGraph&>(*graph.getGraph()));
202 attachEndOfAlternative(idiomaticVertex,
203 result.back().getVertex(),const_cast<LinguisticGraph&>(*graph.getGraph()));
204
205 // if expression is not contextual, only keep alternative
206 if (! result.isContextual())
207 {
208 recoData->storeVerticesToRemove(result,const_cast<LinguisticGraph*>(graph.getGraph()));
209 removeEdges(const_cast<LinguisticGraph&>(*graph.getGraph()),
210 result, analysis);
211 //recoData->setNextVertex(idiomaticVertex);
212 // if match was on single token, use next vertices (to avoid loops)
213 if (result.size() > 1)
214 {
215 recoData->setNextVertex(idiomaticVertex);
216 }
217 else
218 {
219 LinguisticGraphOutEdgeIt outItr,outItrEnd;
220 boost::tie(outItr,outItrEnd) = out_edges(idiomaticVertex,*(graph.getGraph()));
221 for (;outItr!=outItrEnd;outItr++)
222 {
223 recoData->setNextVertex(target(*outItr, *(graph.getGraph())));
224 }
225 }
226 }
227 }
228 else
229 {
230 // several parts : tough case
231// MORPHOLOGINIT;
232// LDEBUG << "non contiguous idiomatic expression found: "
233// << result.concatString();
234
235 // check if there is an overlap first
236 if (recoData->matchOnRemovedVertices(result))
237 {
238 // ignore current idiomatic expression, continue
240 LWARN << "idiomatic expression ignored: " << Common::Misc::limastring2utf8stdstring(result.concatString())
241 << ": overlapping with a previous one";
242 return false;
243 }
244
245 // create the new token
246 pair<Token*,MorphoSyntacticData*> newToken = createAlternativeToken(result);
247 if (newToken.second->empty())
248 {
249 // ignore current idiomatic expression, continue
251 LERROR << "CreateIdiomaticAlternative::operator() Got empty morphosyntactic data. Abort";
252 delete newToken.first;
253 delete newToken.second;
254 return false;
255 }
256
257 // add the vertex
258 LinguisticGraphVertex idiomaticVertex =
259 addAlternativeVertex(newToken.first,newToken.second,const_cast<LinguisticGraph*>(graph.getGraph()));
260 addedVertices.insert(idiomaticVertex);
261 AnnotationGraphVertex agv = annotationData->createAnnotationVertex();
262 annotationData->addMatching("AnalysisGraph", idiomaticVertex, "annot", agv);
263 annotationData->annotate(agv, Common::Misc::utf8stdstring2limastring("AnalysisGraph"), idiomaticVertex);
264 IdiomaticExpressionAnnotation annot(result);
265 GenericAnnotation ga(annot);
266 annotationData->annotate(agv, Common::Misc::utf8stdstring2limastring("IdiomExpr"), ga);
267
268 //create the alternative with this vertex and duplicate of other vertices
269 deque<LinguisticGraphVertex> idiomAlternative;
270 LinguisticGraphVertex headVertex=result.getHead();
271#ifdef DEBUG_LP
272 LDEBUG << "headVertex = " << headVertex;
273 if (headVertex!=0)
274 {
275 LDEBUG << "=> " << Common::Misc::limastring2utf8stdstring(get(vertex_token,*graph.getGraph(),headVertex)->stringForm());
276 }
277#endif
278 bool foundHead=false;
279 bool keeping = false;
280 std::pair< LinguisticGraphVertex, LinguisticGraphVertex > idiomPartBounds;
281 std::set< std::pair< LinguisticGraphVertex, LinguisticGraphVertex > > edgesToRemove;
282 RecognizerMatch::const_iterator matchItr=result.begin();
283 for (; matchItr!=result.end(); matchItr++)
284 {
285 if (!matchItr->isKept())
286 {
287 if (keeping)
288 {
289 RecognizerMatch::const_iterator prevItr = matchItr - 1;
290 idiomPartBounds.second = prevItr->getVertex();
291 keeping = false;
292#ifdef DEBUG_LP
293 LDEBUG << "adding " << idiomPartBounds.first << " -> " << idiomPartBounds.second << " in edgesToRemove";
294#endif
295 edgesToRemove.insert(idiomPartBounds);
296 }
297 // duplicate this vertex
298#ifdef DEBUG_LP
299 LDEBUG << "duplication of vertex " << matchItr->getVertex();;
300#endif
301 Token* token=get(vertex_token,*graph.getGraph(),matchItr->getVertex());
302 MorphoSyntacticData* data =
303 new MorphoSyntacticData(*get(vertex_data,*graph.getGraph(),matchItr->getVertex()));
304 LinguisticGraphVertex dupVx = add_vertex(const_cast<LinguisticGraph&>(*graph.getGraph()));
305 put(vertex_token,const_cast<LinguisticGraph&>(*graph.getGraph()),dupVx,token);
306 put(vertex_data,const_cast<LinguisticGraph&>(*graph.getGraph()),dupVx,data);
307 idiomAlternative.push_back(dupVx);
308 AnnotationGraphVertex agv = annotationData->createAnnotationVertex();
309 annotationData->addMatching("AnalysisGraph", dupVx, "annot", agv);
310 annotationData->annotate(agv, Common::Misc::utf8stdstring2limastring("AnalysisGraph"), dupVx);
311 std::set< LinguisticGraphVertex > annotMatches =
312 annotationData->matches("AnalysisGraph",matchItr->getVertex(),"annot");
313 for (std::set< LinguisticGraphVertex >::const_iterator annotIt(annotMatches.begin());
314 annotIt != annotMatches.end(); annotIt++)
315 {
316 std::set< std::string > excepted;
317 excepted.insert("AnalysisGraph");
318 annotationData->cloneAnnotations(*annotIt, agv, excepted);
319 }
320 addedVertices.insert(dupVx);
321// verticesToRemove.insert(matchItr->getVertex());
322 }
323 else
324 {
325 if (!keeping)
326 {
327 idiomPartBounds.first = matchItr->getVertex();
328 keeping = true;
329 }
330#ifdef DEBUG_LP
331 LDEBUG << "kept vertex " << matchItr->getVertex();
332#endif
333 if (matchItr->getVertex()==headVertex)
334 {
335 foundHead=true;
336#ifdef DEBUG_LP
337 LDEBUG << "add head vertex " << idiomaticVertex;
338#endif
339 idiomAlternative.push_back(idiomaticVertex);
340 }
341 }
342 }
343 if (!foundHead)
344 {
346 LWARN << "head token has not been found in non contiguous expression. "
347 << "Idiomatic token is placed first";
348 idiomAlternative.push_front(idiomaticVertex);
349 }
350 if (keeping)
351 {
352 RecognizerMatch::const_iterator prevItr = matchItr - 1;
353 idiomPartBounds.second = prevItr->getVertex();
354 keeping = false;
355#ifdef DEBUG_LP
356 LDEBUG << "adding " << idiomPartBounds.first << " -> " << idiomPartBounds.second << " in edgesToRemove";
357#endif
358 edgesToRemove.insert(idiomPartBounds);
359 }
360
361 // link alternatives
362#ifdef DEBUG_LP
363 LDEBUG << "idiomAlternative has " << idiomAlternative.size() << " vertex";
364#endif
365 createBeginAlternative(result.front().getVertex(),
366 idiomAlternative.front(),const_cast<LinguisticGraph&>(*graph.getGraph()));
367 {
368 deque<LinguisticGraphVertex>::const_iterator idItr=idiomAlternative.begin();
369 LinguisticGraphVertex lastIdiomVx=*idItr;
370 idItr++;
371 while (idItr!=idiomAlternative.end())
372 {
373 LinguisticGraphEdge newEdge;
374 bool ok;
375 boost::tie(newEdge, ok) = add_edge(lastIdiomVx,*idItr,const_cast<LinguisticGraph&>(*graph.getGraph()));
376#ifdef DEBUG_LP
377 LDEBUG << "added new edge in alternatives linking: " << newEdge.m_source << " -> " << newEdge.m_target;
378#endif
379 lastIdiomVx=*idItr;
380 idItr++;
381 }
382 }
383 attachEndOfAlternative(idiomAlternative.back(),
384 result.back().getVertex(),const_cast<LinguisticGraph&>(*graph.getGraph()));
385
386 // if expression is not contextual, only keep alternative
387 if (! result.isContextual())
388 {
389#ifdef DEBUG_LP
390 LDEBUG << "expression is not contextual, only keep alternative";
391#endif
392 std::set< std::pair< LinguisticGraphVertex, LinguisticGraphVertex > >::const_iterator edgesToRemoveIt, edgesToRemoveIt_end;
393 edgesToRemoveIt = edgesToRemove.begin(); edgesToRemoveIt_end = edgesToRemove.end();
394 for (; edgesToRemoveIt != edgesToRemoveIt_end; edgesToRemoveIt++)
395 {
396#ifdef DEBUG_LP
397 LDEBUG << "Removing edge " << (*edgesToRemoveIt).first << " -> " << (*edgesToRemoveIt).second;
398#endif
399 removeEdges(const_cast<LinguisticGraph&>(*graph.getGraph()),
400 result, analysis);
401 }
402
403// recoData->storeVerticesToRemove(result,*graph);
404 // no need to check size: if several parts, more than one vertex
405 recoData->setNextVertex(idiomaticVertex);
406
407 }
408 }
409 RecognizerMatch::const_iterator matchItr=result.begin();
410 for (; matchItr!=result.end(); matchItr++)
411 {
412 recoData->clearUnreachableVertices( analysis, (*matchItr).getVertex());
413 }
414// recoData->clearUnreachableVertices( analysis, result.front().getVertex(), result.back().getVertex(), storedEdges);
415 return true;
416}
417
418
419} // MorphologicAnalysis
420
421} // LinguisticProcessing
422
423} // Lima
This file is the main header file for the data related to annotation graphs.
#define CreateIdiomaticAlternativeId
#define LWARN
Definition LimaCommon.h:160
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
LinguisticGraph::in_edge_iterator LinguisticGraphInEdgeIt
boost::graph_traits< LinguisticGraph >::edge_descriptor LinguisticGraphEdge
typedefs to simplify the access to various graphs elements
@ vertex_token
LinguisticGraph::vertex_descriptor LinguisticGraphVertex
@ vertex_data
LinguisticGraph::out_edge_iterator LinguisticGraphOutEdgeIt
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, LinguisticVertexProperties > LinguisticGraph
Property to identify the chains in the graph.
#define MORPHOLOGINIT
Data used for the syntactic analyzis of texts.
Holds all data that pass through the ProcessUnits Analysis data are shared pointers,...
std::shared_ptr< AnalysisData > getData(const QString &id)
return AnalysisData by id
This class allows to convert any object into an annotation by inheritance.
LinguisticGraphVertex addAlternativeVertex(LinguisticAnalysisStructure::Token *, LinguisticAnalysisStructure::MorphoSyntacticData *, LinguisticGraph *graph) const
std::pair< LinguisticAnalysisStructure::Token *, LinguisticAnalysisStructure::MorphoSyntacticData * > createAlternativeToken(const Automaton::RecognizerMatch &recognizedExpression) const
Creates the new token corresponding to the idiomatic expression using information from the expression...
void createBeginAlternative(LinguisticGraphVertex startVertex, LinguisticGraphVertex alternativeFirstVertex, LinguisticGraph &graph) const
create an alternative branch
void attachEndOfAlternative(LinguisticGraphVertex alternativeLastVertex, LinguisticGraphVertex endVertex, LinguisticGraph &graph) const
attach the end of an alternative to main path
const LinguisticAnalysisStructure::AnalysisGraph * getGraph() const
An AnalysisData containing a LinguisticGraph with a language and an id.
const LinguisticGraph * getGraph(void) const
Returns the underlying graph structure.
CreateIdiomaticAlternative(MediaId language, const LimaString &complement=LimaString())
virtual bool operator()(Automaton::RecognizerMatch &match, AnalysisContent &analysis) const override
zero-ary constraint function : applies the function without a vertex indication (used for actions,...
Definition of a function suitable to be used as a dumper for idiomatic expressions annotations of an ...
AnnotationGraph::vertex_descriptor AnnotationGraphVertex
std::string limastring2utf8stdstring(const Lima::LimaString &phrase, uint32_t size0)
Convert a wide string to a string , in dest up to size bytes.
LimaString utf8stdstring2limastring(const std::string &src)
ConstraintFunctionFactory< CreateIdiomaticAlternative > CreateIdiomaticAlternativeFactory(CreateIdiomaticAlternativeId)
NAUTITIA.
QString LimaString
Definition LimaString.h:33
STL namespace.