Gaia
searchspace_impl.h
1 /*
2  * Copyright (C) 2006-2013 Music Technology Group - Universitat Pompeu Fabra
3  *
4  * This file is part of Gaia
5  *
6  * Gaia is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License as published by the Free
8  * Software Foundation (FSF), either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the Affero GNU General Public License
17  * version 3 along with this program. If not, see http://www.gnu.org/licenses/
18  */
19 
20 #include <algorithm>
21 
22 template <typename SearchPointType, typename DataSetType>
23 BaseSearchSpace<SearchPointType, DataSetType>::BaseSearchSpace(const Filter* filter, bool ownsFilter)
24  : _dataset(0), _filter(filter), _ownsFilter(ownsFilter), _sortedUpTo(0), _filteredUpTo(0) {
25  // NB: we can probably optimize out filtering here: if (!_filter) isEveryoneFiltered = true;
26 }
27 
28 template <typename SearchPointType, typename DataSetType>
29 BaseSearchSpace<SearchPointType, DataSetType>::BaseSearchSpace(const BaseSearchSpace<SearchPointType, DataSetType>& other)
30  : _dataset(0), _filter(0), _ownsFilter(false), _sortedUpTo(0), _filteredUpTo(0) {
31 
32  copyPointsFrom(other);
33 }
34 
35 
36 template <typename SearchPointType, typename DataSetType>
37 void BaseSearchSpace<SearchPointType, DataSetType>::copyPointsFrom(const BaseSearchSpace<SearchPointType, DataSetType>& other) {
38  // WARNING: TODO: here we first filter all points from other (due to size() instead of Base::size())
39  // this might slow things down if it's not what we want...
40  int size = other.size();
41  this->resize(size);
42  memcpy(&(*this)[0], &other[0], size*sizeof(SearchPointType));
43  this->setDataSet(other.dataSet());
44 }
45 
46 template <typename SearchPointType, typename DataSetType>
47 BaseSearchSpace<SearchPointType, DataSetType>::~BaseSearchSpace() {
48  if (_ownsFilter) delete _filter;
49 }
50 
51 template <typename SearchPointType, typename DataSetType>
53  BaseSearchSpace<SearchPointType, DataSetType>* space = const_cast<BaseSearchSpace<SearchPointType, DataSetType>*>(this);
54  space->filterAll();
55 
56  return unfilteredSize();
57 }
58 
59 template <typename SearchPointType, typename DataSetType>
61  return (int)Vector<SearchPointType>::size();
62 }
63 
64 template <typename SearchPointType, typename DataSetType>
65 void BaseSearchSpace<SearchPointType, DataSetType>::cleanSearchSpace() {
66  _dataset = 0;
67  if (_ownsFilter) delete _filter;
68  _filter = 0;
69  _ownsFilter = false;
70  invalidate();
71 }
72 
73 
74 template <typename SearchPointType, typename DataSetType>
75 SearchResults BaseSearchSpace<SearchPointType, DataSetType>::get(int n, int offset) {
76  if (offset + n > validUpTo()) {
77  // should be able to sort only part of it if necessary, like if offset is small
78  filterAll();
79  sortAll();
80  }
81 
82  SearchResults result;
83  offset = qMin(offset, (int)size());
84  int end = qMin(offset+n, (int)size());
85  for (int i=offset; i<end; i++) {
86  result << qMakePair(this->pointName(this->at(i)), this->at(i).dist);
87  }
88 
89  return result;
90 }
91 
92 template <typename SearchPointType, typename DataSetType>
93 inline void BaseSearchSpace<SearchPointType, DataSetType>::setFilter(const Filter* filter, bool ownsFilter) {
94  if (_ownsFilter) delete _filter;
95 
96  _filter = filter;
97  _ownsFilter = ownsFilter;
98 
99  _filteredUpTo = 0;
100 }
101 
102 
103 template <typename SearchPointType, typename DataSetType>
105  int size = unfilteredSize();
106 
107  // for trivial filters, we can consider all the points already filtered
108  if (!_filter || _filter->isAlwaysTrue()) _filteredUpTo = size;
109  if (_filteredUpTo == size) return;
110 
111  Q_ASSERT(_filteredUpTo <= size);
112  Q_ASSERT(_sortedUpTo <= size);
113 
114  int lastAccepted = _filteredUpTo;
115 
116  for (int i=_filteredUpTo; i<size; i++) {
117  if (this->validPoint(this->at(i))) {
118  this->at(lastAccepted) = this->at(i);
119  lastAccepted++;
120  }
121  // if we "remove" one point which had already been sorted, we also need to decrement the
122  // number of sorted points
123  else if (_sortedUpTo > i) {
124  _sortedUpTo--;
125  }
126  }
127 
128  this->resize(lastAccepted);
129  _filteredUpTo = lastAccepted;
130 }
131 
132 
133 template <typename SearchPointType, typename DataSetType>
134 void BaseSearchSpace<SearchPointType, DataSetType>::sortAll() {
135  // make sure you only call this function with all your points previously filtered
136  Q_ASSERT(_filteredUpTo == unfilteredSize());
137  gaia2::sort(this->begin() + _sortedUpTo, this->end());
138  _sortedUpTo = (int)Vector<SearchPointType>::size();
139 }
140 
141 
142 
143 template <typename SearchPointType, typename DataSetType>
145  Q_ASSERT(_filteredUpTo <= unfilteredSize());
146  Q_ASSERT(_sortedUpTo <= unfilteredSize());
147  filterAndSort(n);
148  Vector<SearchPointType>::resize(qMin(n, unfilteredSize()));
149 }
150 
151 
152 template <typename SearchPointType, typename DataSetType>
154  invalidate();
155  Vector<SearchPointType>::clear();
156 }
157 
158 template <typename SearchPointType, typename DataSetType>
160  Q_ASSERT(_filteredUpTo <= unfilteredSize());
161  Q_ASSERT(_sortedUpTo <= unfilteredSize());
162 
163  float maxValidDist = -1;
164  int validIdx = validUpTo();
165  int start = 0, end = 0;
166 
167  if (validIdx > 0) maxValidDist = this->at(validIdx-1).dist;
168  if (maxValidDist < maxDist) {
169  filterAll();
170  sortAll();
171  end = unfilteredSize();
172  }
173  else {
174  end = validIdx;
175  }
176 
177  if (end == 0) return; // space is empty, don't do anything stupid
178 
179  // find the cutoff point using a binary search
180  if (maxDist < this->at(start).dist) { clear(); return; }
181  if (maxDist > this->at(end-1).dist) { return; }
182 
183  while ((end - start) > 1) {
184  int pivotIdx = (start + end) / 2;
185  float distm = this->at(pivotIdx).dist;
186  if (distm > maxDist) end = pivotIdx;
187  else start = pivotIdx;
188  }
189 
190  // we have start + 1 == end
191  int finalSize = start;
192  //if (at(start).dist <= maxDist) finalSize = end-1;
193  finalSize++;
194 
195  this->resize(finalSize);
196  _filteredUpTo = qMin(_filteredUpTo, finalSize);
197  _sortedUpTo = qMin(_sortedUpTo, finalSize);
198 }
199 
200 template <typename SearchPointType, typename DataSetType>
202  int size = unfilteredSize();
203 
204  Q_ASSERT(_filteredUpTo <= size);
205  Q_ASSERT(_sortedUpTo <= size);
206 
207  if (n < 0 || n > size) n = size;
208 
209  if (_filteredUpTo >= n && _sortedUpTo >= n) return;
210 
211  filterAll();
212  n = qMin(n, unfilteredSize());
213 
214  std::partial_sort(this->begin(), this->begin() + n, this->end());
215  _sortedUpTo = n;
216 }
217 
218 
219 template <typename SearchPointType, typename DataSetType>
220 void BaseSearchSpace<SearchPointType, DataSetType>::addPoints(const DataSetType* dataset, const QList<QString>& ids) {
221  foreach (const QString& id, ids) {
222  this->push_back(SearchPointType(dataset->point(id),
223  dataset->referenceDataSet()->point(id)));
224  }
225 }
226 
227 template <typename SearchPointType, typename DataSetType>
228 void BaseSearchSpace<SearchPointType, DataSetType>::removePoints(const QList<QString>& ids) {
229  QList<int> positionsToRemove;
230  QSet<QString> idSet = QSet<QString>::fromList(ids);
231 
232  // first find positions of all the elements to remove
233  for (typename BaseSearchSpace<SearchPointType, DataSetType>::const_iterator it = this->begin(); it != this->end(); ++it) {
234  if (idSet.contains(it->ptr->name())) {
235  positionsToRemove << (it - this->begin());
236  }
237  }
238 
239  // then remove them all in 1 go
240  sort(positionsToRemove.begin(), positionsToRemove.end());
241 
242  // TODO: this is not the most efficient way to do it...
243  for (int i=(int)positionsToRemove.size()-1; i>=0; i--) {
244  this->erase(this->begin() + positionsToRemove[i]);
245  }
246 
247  // update values for _sortedUpto and _filteredUpTo, as they might now be bigger
248  // than the size of our BaseSearchSpace
249  int size = unfilteredSize();
250  _sortedUpTo = qMin(_sortedUpTo, size);
251  _filteredUpTo = qMin(_filteredUpTo, size);
252 }
253 
254 
255 template <typename SearchPointType>
256 inline bool pointerOrderCompare(const SearchPointType& p1, const SearchPointType& p2);
257 
258 
259 template <>
260 inline bool pointerOrderCompare(const SearchPoint& p1, const SearchPoint& p2) {
261  return p1.ptr < p2.ptr;
262 }
263 
264 template <>
265 inline bool pointerOrderCompare(const FrozenSearchPoint& p1, const FrozenSearchPoint& p2) {
266  return p1.idx < p2.idx;
267 }
268 
269 template <typename SearchPointType, typename DataSetType>
271  gaia2::sort(range(*this), pointerOrderCompare<SearchPointType>);
272  invalidate();
273 }
274 
275 template <typename SearchPointType, typename DataSetType>
276 void BaseSearchSpace<SearchPointType, DataSetType>::setIntersection(const BaseSearchSpace* other) {
277  Q_ASSERT(_filteredUpTo == 0);
278  Q_ASSERT(_sortedUpTo == 0);
279 
280  typename Vector<SearchPointType>::iterator end = std::set_intersection(range(*this),
281  range(*other),
282  this->begin(), pointerOrderCompare<SearchPointType>);
283  this->resize(end - this->begin());
284 }
285 
286 template <typename SearchPointType, typename DataSetType>
287 void BaseSearchSpace<SearchPointType, DataSetType>::setDifference(const BaseSearchSpace* other) {
288  Q_ASSERT(_filteredUpTo == 0);
289  Q_ASSERT(_sortedUpTo == 0);
290 
291  typename Vector<SearchPointType>::iterator end = std::set_difference(range(*this),
292  range(*other),
293  this->begin(), pointerOrderCompare<SearchPointType>);
294  this->resize(end - this->begin());
295 }
296 
297 template <typename SearchPointType, typename DataSetType>
298 void BaseSearchSpace<SearchPointType, DataSetType>::setUnion(const BaseSearchSpace* other) {
299  Q_ASSERT(_filteredUpTo == 0);
300  Q_ASSERT(_sortedUpTo == 0);
301 
302  Vector<SearchPointType> tmp;
303  int size = unfilteredSize();
304 
305  tmp.resize(size);
306  memcpy(&tmp[0], &(*this)[0], size * sizeof(SearchPointType));
307 
308  this->resize(size + static_cast<const Vector<SearchPointType>*>(other)->size());
309  typename Vector<SearchPointType>::iterator end = std::set_union(range(tmp),
310  range(*other),
311  this->begin(), pointerOrderCompare<SearchPointType>);
312  this->resize(end - this->begin());
313 
314  Q_ASSERT(_filteredUpTo == 0);
315  Q_ASSERT(_sortedUpTo == 0);
316 }
317 
318 
319 
320 template <typename SearchPointType, typename DataSetType>
321 BaseResultSet<SearchPointType, DataSetType>::BaseResultSet() {
322  _d = new SearchSpaceWrapper<SearchPointType, DataSetType>(new BaseSearchSpace<SearchPointType, DataSetType>());
323 }
324 
325 template <typename SearchPointType, typename DataSetType>
326 BaseResultSet<SearchPointType, DataSetType>::BaseResultSet(BaseSearchSpace<SearchPointType, DataSetType>* sspace) {
327  _d = new SearchSpaceWrapper<SearchPointType, DataSetType>(sspace);
328 }
329 
330 template <typename SearchPointType, typename DataSetType>
331 SearchResults BaseResultSet<SearchPointType, DataSetType>::get(int n, int offset) {
332  return _d->sspace->get(n, offset);
333 }
334 
335 template <typename SearchPointType, typename DataSetType>
336 void BaseResultSet<SearchPointType, DataSetType>::addPoints(const DataSetType* dataset, const QList<QString>& ids) {
337  _d->sspace->addPoints(dataset, ids);
338 }
339 
340 template <typename SearchPointType, typename DataSetType>
341 void BaseResultSet<SearchPointType, DataSetType>::removePoints(const QList<QString>& ids) {
342  _d->sspace->removePoints(ids);
343 }
int unfilteredSize() const
Returns the size of this SearchSpace, before filtering the points.
Definition: searchspace.h:61
void filterAndSort(int n=1000)
Filters the points in this SearchSpace using the given Filter and sort them by increasing distance...
Definition: searchspace.h:202
int size() const
Returns the total number of points contained in this SearchSpace.
Definition: searchspace.h:53
void filterAll()
Filters all points so that the remaining points at the end all comply to the Filter.
Definition: searchspace.h:105
void setUnion(const BaseSearchSpace< SearchPointType, DataSetType > *other)
This computes the union of this SearchSpace with the other one.
Definition: searchspace.h:299
void copyPointsFrom(const BaseSearchSpace< SearchPointType, DataSetType > &other)
Copy all the points from the other SearchSpace into this one.
Definition: searchspace.h:38
void removePoints(const QList< QString > &ids)
Remove the points with the given IDs from this SearchSpace.
Definition: searchspace.h:229
void addPoints(const DataSetType *dataset, const QList< QString > &ids)
Add the points from the dataset with the given IDs to this SearchSpace.
Definition: searchspace.h:221
void clear()
Clears the whole SearchSpace.
Definition: searchspace.h:154
void pointerSort()
Sorts the SearchPoints contained into this SearchSpace by order of their pointer address.
Definition: searchspace.h:271
void thresholdLimit(float maxDist)
This method limits the bymber of results contained in this SearchSpace.
Definition: searchspace.h:160
SearchResults get(int n, int offset=0)
Returns the list of search results, which are pairs of (pointName, distance).
Definition: searchspace.h:332
void limit(int n)
This method limits the number of results contained in this SearchSpace.
Definition: searchspace.h:145
SearchResults get(int n, int offset=0)
Returns the list of search results, which are pairs of (pointName, distance).
Definition: searchspace.h:76
void setDifference(const BaseSearchSpace< SearchPointType, DataSetType > *other)
This computes the difference of this SearchSpace and the other one (ie: this - other).
Definition: searchspace.h:288
void setIntersection(const BaseSearchSpace< SearchPointType, DataSetType > *other)
This computes the intersection of this SearchSpace with the other one.
Definition: searchspace.h:277