LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
bowTokenIterator.cpp
Go to the documentation of this file.
1// Copyright 2002-2013 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6/************************************************************************
7 *
8 * @file bowTokenIterator.cpp
9 * @author Besancon Romaric (romaric.besancon@cea.fr)
10 * @date Thu Feb 9 2006
11 * copyright Copyright (C) 2006-2012 by CEA LIST
12 *
13 ***********************************************************************/
14
15#include "bowTokenIterator.h"
16#include "AbstractBoWElement.h"
17#include "bowTerm.h"
18#include "bowText.h"
19#include "bowComplexToken.h"
20
22#include <algorithm>
23
24
25using namespace std;
26
27namespace Lima {
28namespace Common {
29namespace BagOfWords {
30
32{
33 friend class BoWTokenIterator;
34
35 BoWTokenIteratorPrivate(const BoWText& bowText,
36 const uint64_t nbMaxPartialCompounds=1000,
40
41 // a class to represent complex tokens parts that are stored in
42 // queue: some are pointers to tokens in BoWText, some are
43 // created => keep information for clean delete
44 class BoWTokenPart : public std::pair< boost::shared_ptr< AbstractBoWElement >,bool> {
45 public:
46 BoWTokenPart():std::pair< boost::shared_ptr< AbstractBoWElement >,bool>(boost::shared_ptr< AbstractBoWElement >(),false) {}
47 BoWTokenPart(boost::shared_ptr< AbstractBoWElement > token,bool isCreated):
48 std::pair< boost::shared_ptr< AbstractBoWElement >,bool>(token,isCreated) {}
49
50 ~BoWTokenPart() {}
51
52 const boost::shared_ptr< AbstractBoWElement >& getBoWToken() const { return first; }
53 boost::shared_ptr< AbstractBoWElement >& getBoWToken() { return first; }
54 bool& isCreated() { return second; }
55 bool isCreated() const { return second; }
56 };
57
58 typedef std::deque<BoWTokenPart> BoWTokenQueue;
59
60
61 // members
62 BoWText::const_iterator m_iterator;
63 BoWText::const_iterator m_iteratorEnd;
64 BoWTokenQueue m_partQueue;
65 uint64_t m_maxSizeQueue;
66
69 BoWTokenIteratorNamedEntitiesPartsPolicy m_iterateThroughNamedEntitiesParts;
70
71
72 // private methods
73
74 // add in queue
75 // (return false if size of queue becomes greater than max)
76 bool addInPartQueue(boost::shared_ptr< BoWToken > token,
77 const bool isCreated);
78
79 void storePartsInQueue(boost::shared_ptr< BoWToken > token);
80
81 // a type to store interesting parts of complex tokens
82 // (the parts used to be combined to create partial complex tokens)
83 typedef std::vector<boost::shared_ptr< BoWToken > > PartTokens;
84
85 // recursive function to get all parts of complex token
86 // and create partial complex tokens
87 // (return false if size of queue becomes greater than max)
88 bool addPartElementsInQueue(boost::shared_ptr< Lima::Common::BagOfWords::BoWToken > token, vector< Lima::Common::BagOfWords::BoWTokenIteratorPrivate::PartTokens >& partTokens);
89
103 bool addCombinedPartsInQueue(const std::vector<PartTokens>& subPartTokens,
104 const uint64_t head,
105 PartTokens& createdTokens,
106 PartTokens& currentPartialToken,
107 const uint64_t i,
108 bool& first);
116 boost::shared_ptr< BoWComplexToken > createComplexToken(const PartTokens& parts);
117};
118
119BoWTokenIteratorPrivate::BoWTokenIteratorPrivate(const BoWText& bowText,
120 const uint64_t nbMaxPartialCompounds,
121 BoWTokenIteratorNamedEntitiesPartsPolicy iterateThroughNamedEntitiesParts):
122m_iterator(bowText.begin()),
123m_iteratorEnd(bowText.end()),
124m_partQueue(),
125m_maxSizeQueue(nbMaxPartialCompounds),
126m_iterateThroughNamedEntitiesParts(iterateThroughNamedEntitiesParts)
127{
128}
129
130BoWTokenIteratorPrivate::BoWTokenIteratorPrivate(const BoWTokenIteratorPrivate& btip)
131{
132 m_iterator = btip.m_iterator;
133 m_iteratorEnd = btip.m_iteratorEnd;
134 m_partQueue = btip.m_partQueue;
135 m_maxSizeQueue = btip.m_maxSizeQueue;
136 m_iterateThroughNamedEntitiesParts = btip.m_iterateThroughNamedEntitiesParts;
137}
138
139BoWTokenIteratorPrivate::~BoWTokenIteratorPrivate()
140{
141}
142
143
144//**********************************************************************
145// iterator functions
146//**********************************************************************
148 const uint64_t nbMaxPartialCompounds,
149 BoWTokenIteratorNamedEntitiesPartsPolicy iterateThroughNamedEntitiesParts):
150 m_d(new BoWTokenIteratorPrivate(bowText, nbMaxPartialCompounds, iterateThroughNamedEntitiesParts))
151{
152}
153
155 m_d(new BoWTokenIteratorPrivate(*bti.m_d))
156{
157}
158
160{
161 delete m_d;
162}
163
165 return (m_d->m_iterator == m_d->m_iteratorEnd);
166}
167
168//**********************************************************************
169// get current element ("dereference" iterator)
170//**********************************************************************
171// getting parts is done in this function (rather than in ++ function):
172// which means that is a ++ is done before calling a getElement on
173// a complex token, no parts will be explored
174boost::shared_ptr< AbstractBoWElement > BoWTokenIterator::getElement() {
175 if (m_d->m_partQueue.empty()) {
176 if (m_d->m_iterator==m_d->m_iteratorEnd) { // at end
177 return boost::shared_ptr< AbstractBoWElement >();
178 }
179 else {
180 switch ((*m_d->m_iterator)->getType()) {
182 case BoWType::BOW_TOKEN: {
183 return *m_d->m_iterator;
184 break;
185 }
188 // element itself will be stored in queue as part
189 m_d->storePartsInQueue(boost::dynamic_pointer_cast< BoWToken >(*m_d->m_iterator));
190 return m_d->m_partQueue.front().getBoWToken();
191 break;
192 }
193 default: ;
194 }
195 }
196 }
197 else {
198 return m_d->m_partQueue.front().getBoWToken();
199 }
200 return boost::shared_ptr< AbstractBoWElement >();
201}
202
203//**********************************************************************
204// operator ++
205//**********************************************************************
207{
208 if (m_d->m_partQueue.empty()) {
209 if (m_d->m_iterator!=m_d->m_iteratorEnd) {
210 m_d->m_iterator++;
211 }
212 }
213 else {
214 m_d->m_partQueue.pop_front();
215 if (m_d->m_partQueue.empty()) { // finished for the parts of this token
216 m_d->m_iterator++;
217 }
218 }
219 return *this;
220}
221
222// postfix ++ operator
224 BoWTokenIterator it = *this;
225 ++(*this);
226 return it;
227}
228
229//**********************************************************************
230// helper functions for iterator
231//**********************************************************************
232bool BoWTokenIteratorPrivate::addInPartQueue(const boost::shared_ptr< BoWToken > token,
233 const bool isCreated)
234{
235 if (m_partQueue.size() >= m_maxSizeQueue) {
237 LWARN << "size of queue exceeded";
238 return false;
239 }
240 // avoid call to copy constructor (ensure pointer copy)
241 m_partQueue.push_back(BoWTokenPart());
242 m_partQueue.back().getBoWToken()=token;
243 m_partQueue.back().isCreated()=isCreated;
245 LDEBUG << "add in part queue " << *token
246 << "; isCreated=" << isCreated
247 << "size of queue=" << m_partQueue.size()
248 ;
249 return true;
250}
251
252void BoWTokenIteratorPrivate::storePartsInQueue(boost::shared_ptr< BoWToken > token) {
253 vector<vector<boost::shared_ptr< BoWToken > > > partTokens;
254 if (!addPartElementsInQueue(token,partTokens)) {
256 LWARN << "Token contain too many subparts (some are ignored): "
257 << token->getLemma();
258 }
259}
260
261bool BoWTokenIteratorPrivate::addPartElementsInQueue(boost::shared_ptr< BoWToken > token,
262 vector<PartTokens>& partTokens) {
263
265 LDEBUG << "getPartElements on " << *token;
266
267 // push token itself
268 if (! addInPartQueue(token,false)) {
269 return false;
270 }
271// addInPartQueue(token,false);
272 if (token->getType()==BoWType::BOW_NAMEDENTITY
273 && m_iterateThroughNamedEntitiesParts==DO_NOT_ITERATE_THROUGH_NAMEDENTITIES_PARTS)
274 {
275 PartTokens pt;
276 partTokens.push_back(pt);
277 partTokens.back().push_back(token);
278 return true;
279 }
280
281 switch (token->getType()) {
282 case BoWType::BOW_TOKEN: {
283 // push simple token in parts
284 partTokens.push_back(PartTokens());
285 partTokens.back().push_back(token);
286 break;
287 }
290 boost::shared_ptr< BoWComplexToken > complexToken=boost::dynamic_pointer_cast<BoWComplexToken>(token);
291
292 if (complexToken->size() == 1) {
293 // only one part, do not get into it
294 // (for instance, named entity with one element)
295 // push simple token in parts
296 partTokens.push_back(PartTokens());
297 partTokens.back().push_back(token);
298 return true;
299 }
300
301 // add new vector for token parts
302 partTokens.push_back(PartTokens());
303
304 // push token itself and head
305 LDEBUG << "storing token " << *token;
306 partTokens.back().push_back(token);
307 const BoWComplexToken::Part& headPart=complexToken->getParts()[complexToken->getHead()];
308 LDEBUG << "storing head token " << *(headPart.getBoWToken());
309 partTokens.back().push_back(headPart.getBoWToken());
310
311 // treat parts
312 vector<PartTokens> subPartTokens;
313
314 deque<BoWComplexToken::Part>::const_iterator
315 part=complexToken->getParts().begin(),
316 part_end=complexToken->getParts().end();
317
318 for (; part!=part_end; part++) {
319 if (!addPartElementsInQueue((*part).getBoWToken(),subPartTokens)) {
320 return false;
321 }
322 }
323
324 if (subPartTokens.size()>1) {
325 PartTokens combined;
326 PartTokens currentPartialToken;
327 bool first(true);
328 if (!addCombinedPartsInQueue(subPartTokens,complexToken->getHead(),
329 combined,currentPartialToken,0,first)) {
330 return false;
331 }
332 // add created partial tokens in parts
333 partTokens.back().insert(partTokens.back().end(),combined.begin(),combined.end());
334 }
335 break;
336 }
337 default: ;
338 }
339 return true;
340}
341
342
343bool BoWTokenIteratorPrivate::addCombinedPartsInQueue(const vector< Lima::Common::BagOfWords::BoWTokenIteratorPrivate::PartTokens >& subPartTokens, const uint64_t head, Lima::Common::BagOfWords::BoWTokenIteratorPrivate::PartTokens& createdTokens, Lima::Common::BagOfWords::BoWTokenIteratorPrivate::PartTokens& currentPartialToken, const uint64_t i, bool& first)
344{
345 if (i>=subPartTokens.size()) {
346 if (first) {
347 // do not create token for first combination: corresponds
348 // the token itself (the one in BoWText, that has already
349 // added in queue)
350 first=false;
351 return true;
352 }
353
354 if (currentPartialToken.size() == 1) {
355 //just the head: is already in queue
356 return true;
357 }
358
359 // at end of parts => add current currentPartialToken
360 boost::shared_ptr< BoWComplexToken > partialComplexToken=
361 createComplexToken(currentPartialToken);
362
363 if (partialComplexToken!=0) {
364 if (! addInPartQueue(partialComplexToken,true)) {
365 return false;
366 }
367 // addInPartQueue(partialComplexToken,true);
368 createdTokens.push_back(partialComplexToken);
369 }
370 return true;
371 }
372
373 // add possible at end of currentPartialToken and recursive call
374 for (auto it=subPartTokens[i].begin(),it_end=subPartTokens[i].end();
375 it!=it_end; it++) {
376 currentPartialToken.push_back(*it);
377 if (!addCombinedPartsInQueue(subPartTokens,head,
378 createdTokens,currentPartialToken,
379 i+1,first)) {
380 return false;
381 }
382 currentPartialToken.pop_back();
383 }
384 // if head, stop here: current iterator is head, hence always added
385 // otherwise, recursive call without current iterator (that is an
386 // extension)
387 if (i!=head) {
388 if (!addCombinedPartsInQueue(subPartTokens,head,
389 createdTokens,currentPartialToken,
390 i+1,first)) {
391 return false;
392 }
393 }
394 return true;
395}
396
397//**********************************************************************
398// create a partial complex token
399boost::shared_ptr< BoWComplexToken > BoWTokenIteratorPrivate::createComplexToken(const PartTokens& parts) {
400
401// BOWLOGINIT;
402// LDEBUG << "create complex token";
403
404 boost::shared_ptr< BoWTerm > partialComplexToken(new BoWTerm);
405
406 // do not set lemma of partial token : do not store computed lemmas
407 // for compounds
408
409 for (auto it=parts.begin(), it_end=parts.end(); it!=it_end; it++) {
410 partialComplexToken->addPart(boost::dynamic_pointer_cast<BoWToken>(*it));
411 }
412 // set position and length
414 poslenlist=partialComplexToken->getPositionLengthList();
415 // have to sort positions
416 std::sort(poslenlist.begin(),poslenlist.end());
417 if (! poslenlist.empty()) {
418 partialComplexToken->setPosition(poslenlist.front().first);
419 partialComplexToken->setLength(poslenlist.back().first+
420 poslenlist.back().second-
421 poslenlist.front().first);
422 }
423
424 return partialComplexToken;
425}
426
427} // end namespace
428} // end namespace
429} // end namespace
#define LWARN
Definition LimaCommon.h:160
#define LDEBUG
Definition LimaCommon.h:157
#define BOWLOGINIT
Definition LimaCommon.h:201
This class is the abstract base class of all elements that can be stored in a BoWText.
This class represents a list of elements, that are pointers on polymmorphic tokens that can be simple...
Definition bowText.h:48
BoWTokenIterator(const BoWText &bowText, const uint64_t nbMaxPartialCompounds=1000, BoWTokenIteratorNamedEntitiesPartsPolicy iterateThroughNamedEntitiesParts=ITERATE_THROUGH_NAMEDENTITIES_PARTS)
constructor
boost::shared_ptr< Lima::Common::BagOfWords::AbstractBoWElement > getElement()
@ BOW_TERM
the AbstractBoWElement is a multi-term
@ BOW_NAMEDENTITY
the AbstractBoWElement is a named entity
@ BOW_TOKEN
the AbstractBoWElement is a simple token
@ BOW_PREDICATE
the AbstractBoWElement is a predicate (n-ary relation, template or semantic frame
std::vector< std::pair< Position, Length > > PositionLengthList
NAUTITIA.
STL namespace.