1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestArrayLookup.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkBitArray.h"
17 #include "vtkIdList.h"
18 #include "vtkIdTypeArray.h"
19 #include "vtkIntArray.h"
20 #include "vtkSortDataArray.h"
21 #include "vtkStringArray.h"
22 #include "vtkTimerLog.h"
23 #include "vtkVariantArray.h"
24 
25 #include "vtkSmartPointer.h"
26 #define VTK_CREATE(type,name) \
27   vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
28 
29 #include <vtksys/stl/vector>
30 #include <vtksys/stl/algorithm>
31 #include <vtksys/stl/utility>
32 #include <vtksys/stl/map>
33 
34 struct NodeCompare
35 {
operator ()NodeCompare36   bool operator()(const vtksys_stl::pair<int, vtkIdType>& a, const vtksys_stl::pair<int, vtkIdType>& b) const
37   {
38     return a.first < b.first;
39   }
40 };
41 
LookupValue(vtksys_stl::multimap<int,vtkIdType> & lookup,int value)42 vtkIdType LookupValue(vtksys_stl::multimap<int, vtkIdType>& lookup, int value)
43 {
44   vtksys_stl::pair<const int, vtkIdType> found = *lookup.lower_bound(value);
45   if (found.first == value)
46     {
47     return found.second;
48     }
49   return -1;
50 }
51 
LookupValue(vtksys_stl::vector<vtksys_stl::pair<int,vtkIdType>> & lookup,int value)52 vtkIdType LookupValue(vtksys_stl::vector<vtksys_stl::pair<int, vtkIdType> >& lookup, int value)
53 {
54   NodeCompare comp;
55   vtksys_stl::pair<int, vtkIdType> val(value, 0);
56   vtksys_stl::pair<int, vtkIdType> found =
57     *vtksys_stl::lower_bound(lookup.begin(), lookup.end(), val, comp);
58   if (found.first == value)
59     {
60     return found.second;
61     }
62   return -1;
63 }
64 
LookupValue(vtkIntArray * lookup,vtkIdTypeArray * index,int value)65 vtkIdType LookupValue(vtkIntArray* lookup, vtkIdTypeArray* index, int value)
66 {
67   int* ptr = lookup->GetPointer(0);
68   vtkIdType place = static_cast<vtkIdType>(vtksys_stl::lower_bound(ptr, ptr + lookup->GetNumberOfTuples(), value) - ptr);
69   if (place < lookup->GetNumberOfTuples() && ptr[place] == value)
70     {
71     return index->GetValue(place);
72     }
73   return -1;
74 }
75 
TestArrayLookupBit(vtkIdType numVal)76 int TestArrayLookupBit(vtkIdType numVal)
77 {
78   int errors = 0;
79 
80   // Create the array
81   vtkIdType arrSize = (numVal-1)*numVal/2;
82   VTK_CREATE(vtkBitArray, arr);
83   for (vtkIdType i = 0; i < arrSize; i++)
84     {
85     arr->InsertNextValue(i < arrSize/2);
86     }
87 
88   //
89   // Test lookup implemented inside data array
90   //
91 
92   // Time the lookup creation
93   VTK_CREATE(vtkTimerLog, timer);
94   timer->StartTimer();
95   arr->LookupValue(0);
96   timer->StopTimer();
97   cerr << "," << timer->GetElapsedTime();
98 
99   // Time simple lookup
100   timer->StartTimer();
101   for (vtkIdType i = 0; i < numVal; i++)
102     {
103     arr->LookupValue(i % 2);
104     }
105   timer->StopTimer();
106   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
107 
108   // Time list lookup
109   VTK_CREATE(vtkIdList, list);
110   timer->StartTimer();
111   for (vtkIdType i = 0; i < numVal; i++)
112     {
113     arr->LookupValue(i % 2, list);
114     }
115   timer->StopTimer();
116   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
117 
118   // Test for correctness (-1)
119   vtkIdType index = -1;
120   index = arr->LookupValue(-1);
121   if (index != -1)
122     {
123     cerr << "ERROR: lookup found value at " << index << " but is not there (should return -1)" << endl;
124     errors++;
125     }
126   arr->LookupValue(-1, list);
127   if (list->GetNumberOfIds() != 0)
128     {
129     cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << 0 << endl;
130     errors++;
131     }
132 
133   // Test for correctness (0)
134   index = arr->LookupValue(0);
135   if (index < arrSize/2 || index > arrSize-1)
136     {
137     cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << arrSize/2 << "," << arrSize-1 << "]" << endl;
138     errors++;
139     }
140   arr->LookupValue(0, list);
141   if (list->GetNumberOfIds() != arrSize - arrSize/2)
142     {
143     cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << arrSize - arrSize/2 << endl;
144     errors++;
145     }
146   else
147     {
148     for (vtkIdType j = 0; j < list->GetNumberOfIds(); j++)
149       {
150       if (arr->GetValue(list->GetId(j)) != 0)
151         {
152         cerr << "ERROR: could not find " << j << " in found list" << endl;
153         errors++;
154         }
155       }
156     }
157 
158   // Test for correctness (1)
159   index = arr->LookupValue(1);
160   if (index < 0 || index > arrSize/2-1)
161     {
162     cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << 0 << "," << arrSize/2-1 << "]" << endl;
163     errors++;
164     }
165   arr->LookupValue(1, list);
166   if (list->GetNumberOfIds() != arrSize/2)
167     {
168     cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << arrSize/2 << endl;
169     errors++;
170     }
171   else
172     {
173     for (vtkIdType j = 0; j < list->GetNumberOfIds(); j++)
174       {
175       if (arr->GetValue(list->GetId(j)) != 1)
176         {
177         cerr << "ERROR: could not find " << j << " in found list" << endl;
178         errors++;
179         }
180       }
181     }
182 
183   return errors;
184 }
185 
TestArrayLookupVariant(vtkIdType numVal)186 int TestArrayLookupVariant(vtkIdType numVal)
187 {
188   int errors = 0;
189 
190   // Create the array
191   vtkIdType arrSize = (numVal-1)*numVal/2;
192   VTK_CREATE(vtkVariantArray, arr);
193   for (vtkIdType i = 0; i < numVal; i++)
194     {
195     for (vtkIdType j = 0; j < numVal-1-i; j++)
196       {
197       arr->InsertNextValue(numVal-1-i);
198       }
199     }
200 
201   //
202   // Test lookup implemented inside data array
203   //
204 
205   // Time the lookup creation
206   VTK_CREATE(vtkTimerLog, timer);
207   timer->StartTimer();
208   arr->LookupValue(0);
209   timer->StopTimer();
210   cerr << "," << timer->GetElapsedTime();
211 
212   // Time simple lookup
213   timer->StartTimer();
214   for (vtkIdType i = 0; i < numVal; i++)
215     {
216     arr->LookupValue(i);
217     }
218   timer->StopTimer();
219   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
220 
221   // Time list lookup
222   VTK_CREATE(vtkIdList, list);
223   timer->StartTimer();
224   for (vtkIdType i = 0; i < numVal; i++)
225     {
226     arr->LookupValue(i, list);
227     }
228   timer->StopTimer();
229   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
230 
231   // Test for correctness
232   vtkIdType correctIndex = arrSize;
233   for (vtkIdType i = 0; i < numVal; i++)
234     {
235     correctIndex -= i;
236     vtkIdType index = arr->LookupValue(i);
237     if (i == 0 && index != -1)
238       {
239       cerr << "ERROR: lookup found value at " << index << " but is at -1" << endl;
240       errors++;
241       }
242     if (i != 0 && (index < correctIndex || index > correctIndex + i - 1))
243       {
244       cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << correctIndex << "," << correctIndex + i - 1 << "]" << endl;
245       errors++;
246       }
247     arr->LookupValue(i, list);
248     if (list->GetNumberOfIds() != i)
249       {
250       cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << i << endl;
251       errors++;
252       }
253     else
254       {
255       for (vtkIdType j = correctIndex; j < correctIndex + i; j++)
256         {
257         bool inList = false;
258         for (vtkIdType k = 0; k < i; ++k)
259           {
260           if (list->GetId(k) == j)
261             {
262             inList = true;
263             break;
264             }
265           }
266         if (!inList)
267           {
268           cerr << "ERROR: could not find " << j << " in found list" << endl;
269           errors++;
270           }
271         }
272       }
273     }
274   return errors;
275 }
276 
TestArrayLookupString(vtkIdType numVal)277 int TestArrayLookupString(vtkIdType numVal)
278 {
279   int errors = 0;
280 
281   // Create the array
282   vtkIdType arrSize = (numVal-1)*numVal/2;
283   VTK_CREATE(vtkStringArray, arr);
284   for (vtkIdType i = 0; i < numVal; i++)
285     {
286     for (vtkIdType j = 0; j < numVal-1-i; j++)
287       {
288       arr->InsertNextValue(vtkVariant(numVal-1-i).ToString());
289       }
290     }
291 
292   //
293   // Test lookup implemented inside data array
294   //
295 
296   // Time the lookup creation
297   VTK_CREATE(vtkTimerLog, timer);
298   timer->StartTimer();
299   arr->LookupValue("0");
300   timer->StopTimer();
301   cerr << "," << timer->GetElapsedTime();
302 
303   // Time simple lookup
304   timer->StartTimer();
305   for (vtkIdType i = 0; i < numVal; i++)
306     {
307     arr->LookupValue(vtkVariant(i).ToString());
308     }
309   timer->StopTimer();
310   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
311 
312   // Time list lookup
313   VTK_CREATE(vtkIdList, list);
314   timer->StartTimer();
315   for (vtkIdType i = 0; i < numVal; i++)
316     {
317     arr->LookupValue(vtkVariant(i).ToString(), list);
318     }
319   timer->StopTimer();
320   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
321 
322   // Test for correctness
323   vtkIdType correctIndex = arrSize;
324   for (vtkIdType i = 0; i < numVal; i++)
325     {
326     correctIndex -= i;
327     vtkIdType index = arr->LookupValue(vtkVariant(i).ToString());
328     if (i == 0 && index != -1)
329       {
330       cerr << "ERROR: lookup found value at " << index << " but is at -1" << endl;
331       errors++;
332       }
333     if (i != 0 && (index < correctIndex || index > correctIndex + i - 1))
334       {
335       cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << correctIndex << "," << correctIndex + i - 1 << "]" << endl;
336       errors++;
337       }
338     arr->LookupValue(vtkVariant(i).ToString(), list);
339     if (list->GetNumberOfIds() != i)
340       {
341       cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << i << endl;
342       errors++;
343       }
344     else
345       {
346       for (vtkIdType j = correctIndex; j < correctIndex + i; j++)
347         {
348         bool inList = false;
349         for (vtkIdType k = 0; k < i; ++k)
350           {
351           if (list->GetId(k) == j)
352             {
353             inList = true;
354             break;
355             }
356           }
357         if (!inList)
358           {
359           cerr << "ERROR: could not find " << j << " in found list" << endl;
360           errors++;
361           }
362         }
363       }
364     }
365   return errors;
366 }
367 
TestArrayLookupInt(vtkIdType numVal,bool runComparison)368 int TestArrayLookupInt(vtkIdType numVal, bool runComparison)
369 {
370   int errors = 0;
371 
372   // Create the array
373   vtkIdType arrSize = (numVal-1)*numVal/2;
374   VTK_CREATE(vtkIntArray, arr);
375   for (vtkIdType i = 0; i < numVal; i++)
376     {
377     for (vtkIdType j = 0; j < numVal-1-i; j++)
378       {
379       arr->InsertNextValue(numVal-1-i);
380       }
381     }
382 
383   //
384   // Test lookup implemented inside data array
385   //
386 
387   // Time the lookup creation
388   VTK_CREATE(vtkTimerLog, timer);
389   timer->StartTimer();
390   arr->LookupValue(0);
391   timer->StopTimer();
392   cerr << "," << timer->GetElapsedTime();
393 
394   // Time simple lookup
395   timer->StartTimer();
396   for (vtkIdType i = 0; i < numVal; i++)
397     {
398     arr->LookupValue(i);
399     }
400   timer->StopTimer();
401   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
402 
403   // Time list lookup
404   VTK_CREATE(vtkIdList, list);
405   timer->StartTimer();
406   for (vtkIdType i = 0; i < numVal; i++)
407     {
408     arr->LookupValue(i, list);
409     }
410   timer->StopTimer();
411   cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
412 
413   // Test for correctness
414   vtkIdType correctIndex = arrSize;
415   for (vtkIdType i = 0; i < numVal; i++)
416     {
417     correctIndex -= i;
418     vtkIdType index = arr->LookupValue(i);
419     if (i == 0 && index != -1)
420       {
421       cerr << "ERROR: lookup found value at " << index << " but is at -1" << endl;
422       errors++;
423       }
424     if (i != 0 && (index < correctIndex || index > correctIndex + i - 1))
425       {
426       cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << correctIndex << "," << correctIndex + i - 1 << "]" << endl;
427       errors++;
428       }
429     arr->LookupValue(i, list);
430     if (list->GetNumberOfIds() != i)
431       {
432       cerr << "ERROR: lookup found " << list->GetNumberOfIds() << " matches but there should be " << i << endl;
433       errors++;
434       }
435     else
436       {
437       for (vtkIdType j = correctIndex; j < correctIndex + i; j++)
438         {
439         bool inList = false;
440         for (vtkIdType k = 0; k < i; ++k)
441           {
442           if (list->GetId(k) == j)
443             {
444             inList = true;
445             break;
446             }
447           }
448         if (!inList)
449           {
450           cerr << "ERROR: could not find " << j << " in found list" << endl;
451           errors++;
452           }
453         }
454       }
455     }
456 
457   if (runComparison)
458     {
459     //
460     // Test STL map lookup
461     //
462 
463     // Time the lookup creation
464     timer->StartTimer();
465     int* ptr = arr->GetPointer(0);
466     vtksys_stl::multimap<int, vtkIdType> map;
467     for (vtkIdType i = 0; i < arrSize; ++i, ++ptr)
468       {
469       map.insert(std::pair<const int, vtkIdType>(*ptr, i));
470       }
471     timer->StopTimer();
472     cerr << "," << timer->GetElapsedTime();
473 
474     // Time simple lookup
475     timer->StartTimer();
476     for (vtkIdType i = 0; i < numVal; i++)
477       {
478       LookupValue(map, i);
479       }
480     timer->StopTimer();
481     cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
482 
483     // Test for correctness
484     correctIndex = arrSize;
485     for (vtkIdType i = 0; i < numVal; i++)
486       {
487       correctIndex -= i;
488       vtkIdType index = LookupValue(map, i);
489       if (i == 0 && index != -1)
490         {
491         cerr << "ERROR: lookup found value at " << index << " but is at -1" << endl;
492         errors++;
493         }
494       if (i != 0 && index != correctIndex)
495         {
496         cerr << "ERROR: lookup found value at " << index << " but is at " << correctIndex << endl;
497         errors++;
498         }
499       }
500 
501     //
502     // Test STL vector lookup
503     //
504 
505     // Time lookup creation
506     timer->StartTimer();
507     ptr = arr->GetPointer(0);
508     vtksys_stl::vector<vtksys_stl::pair<int, vtkIdType> > vec(arrSize);
509     for (vtkIdType i = 0; i < arrSize; ++i, ++ptr)
510       {
511       vec[i] = vtksys_stl::pair<int, vtkIdType>(*ptr, i);
512       }
513     NodeCompare comp;
514     vtksys_stl::sort(vec.begin(), vec.end(), comp);
515     timer->StopTimer();
516     cerr << "," << timer->GetElapsedTime();
517 
518     // Time simple lookup
519     timer->StartTimer();
520     for (vtkIdType i = 0; i < numVal; i++)
521       {
522       LookupValue(vec, i);
523       }
524     timer->StopTimer();
525     cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
526 
527     // Test for correctness
528     correctIndex = arrSize;
529     for (vtkIdType i = 0; i < numVal; i++)
530       {
531       correctIndex -= i;
532       vtkIdType index = LookupValue(vec, i);
533       if (i == 0 && index != -1)
534         {
535         cerr << "ERROR: vector lookup found value at " << index << " but is at -1" << endl;
536         errors++;
537         }
538       if (i != 0 && (index < correctIndex || index > correctIndex + i - 1))
539         {
540         cerr << "ERROR: vector lookup found value at " << index << " but is in range [" << correctIndex << "," << correctIndex + i - 1 << "]" << endl;
541         errors++;
542         }
543       }
544 
545     //
546     // Test sorted data array lookup
547     //
548 
549     // Time lookup creation
550     timer->StartTimer();
551     VTK_CREATE(vtkIdTypeArray, indices);
552     indices->SetNumberOfTuples(arrSize);
553     vtkIdType* keyptr = indices->GetPointer(0);
554     for (vtkIdType i = 0; i < arrSize; ++i, ++keyptr)
555       {
556       *keyptr = i;
557       }
558     VTK_CREATE(vtkIntArray, sorted);
559     sorted->DeepCopy(arr);
560     vtkSortDataArray::Sort(sorted, indices);
561     timer->StopTimer();
562     cerr << "," << timer->GetElapsedTime();
563 
564     // Time simple lookup
565     timer->StartTimer();
566     for (vtkIdType i = 0; i < numVal; i++)
567       {
568       LookupValue(sorted, indices, i);
569       }
570     timer->StopTimer();
571     cerr << "," << (timer->GetElapsedTime() / static_cast<double>(numVal));
572 
573     // Test for correctness
574     correctIndex = arrSize;
575     for (vtkIdType i = 0; i < numVal; i++)
576       {
577       correctIndex -= i;
578       vtkIdType index = LookupValue(sorted, indices, i);
579       if (i == 0 && index != -1)
580         {
581         cerr << "ERROR: arr lookup found value at " << index << " but is at -1" << endl;
582         errors++;
583         }
584       if (i != 0 && (index < correctIndex || index > correctIndex + i - 1))
585         {
586         cerr << "ERROR: arr lookup found value at " << index << " but is in range [" << correctIndex << "," << correctIndex + i - 1 << "]" << endl;
587         errors++;
588         }
589       }
590     }
591 
592   return errors;
593 }
594 
TestArrayLookup(int argc,char * argv[])595 int TestArrayLookup(int argc, char* argv[])
596 {
597   vtkIdType min = 100;
598   vtkIdType max = 200;
599   int steps = 2;
600   bool runComparison = false;
601   for (int i = 0; i < argc; ++i)
602     {
603     if (!strcmp(argv[i], "-C"))
604       {
605       runComparison = true;
606       }
607     if (!strcmp(argv[i], "-m") && i+1 < argc)
608       {
609       ++i;
610       int size = atoi(argv[i]);
611       min = static_cast<int>((-1.0 + sqrt(1 + 8.0*size))/2.0);
612       }
613     if (!strcmp(argv[i], "-M") && i+1 < argc)
614       {
615       ++i;
616       int size = atoi(argv[i]);
617       max = static_cast<int>((-1.0 + sqrt(1 + 8.0*size))/2.0);
618       }
619     if (!strcmp(argv[i], "-S") && i+1 < argc)
620       {
621       ++i;
622       steps = atoi(argv[i]);
623       }
624     }
625 
626   vtkIdType stepSize = (max-min)/(steps-1);
627   if (stepSize <= 0)
628     {
629     stepSize = 1;
630     }
631 
632   int errors = 0;
633   cerr << "distinct values";
634   cerr << ",size";
635   cerr << ",create lookup";
636   cerr << ",index lookup";
637   cerr << ",list lookup";
638   if (runComparison)
639     {
640     cerr << ",create map lookup";
641     cerr << ",index map lookup";
642     cerr << ",create vector lookup";
643     cerr << ",index vector lookup";
644     cerr << ",create array lookup";
645     cerr << ",index array lookup";
646     }
647   cerr << ",string create lookup";
648   cerr << ",string index lookup";
649   cerr << ",string list lookup";
650   cerr << ",variant create lookup";
651   cerr << ",variant index lookup";
652   cerr << ",variant list lookup";
653   cerr << ",bit create lookup";
654   cerr << ",bit index lookup";
655   cerr << ",bit list lookup";
656   cerr << endl;
657   for (vtkIdType numVal = min; numVal <= max; numVal += stepSize)
658     {
659     vtkIdType total = numVal*(numVal+1)/2;
660     cerr << numVal << "," << total;
661     errors += TestArrayLookupInt(numVal, runComparison);
662     errors += TestArrayLookupString(numVal);
663     errors += TestArrayLookupVariant(numVal);
664     errors += TestArrayLookupBit(numVal);
665     cerr << endl;
666     }
667   return errors;
668 }
669