1 package org.ajmm.obsearch.index;
2
3 import hep.aida.bin.QuantileBin1D;
4
5 import java.io.File;
6 import java.io.IOException;
7
8 import org.ajmm.obsearch.OB;
9 import org.ajmm.obsearch.exception.OBException;
10 import org.ajmm.obsearch.exception.OutOfRangeException;
11 import org.apache.log4j.Logger;
12
13 import cern.colt.list.FloatArrayList;
14
15 import com.sleepycat.bind.tuple.IntegerBinding;
16 import com.sleepycat.bind.tuple.TupleInput;
17 import com.sleepycat.je.Cursor;
18 import com.sleepycat.je.Database;
19 import com.sleepycat.je.DatabaseConfig;
20 import com.sleepycat.je.DatabaseEntry;
21 import com.sleepycat.je.DatabaseException;
22 import com.sleepycat.je.LockMode;
23 import com.sleepycat.je.OperationStatus;
24 import com.sleepycat.je.PreloadConfig;
25 import com.thoughtworks.xstream.annotations.XStreamAlias;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 @XStreamAlias("ExtendedPyramidIndex")
55 public abstract class AbstractExtendedPyramidIndex < O extends OB >
56 extends AbstractPivotIndex < O > {
57
58
59
60
61 protected static final int MIN = 0;
62
63
64
65
66 protected static final int MAX = 1;
67
68
69
70
71 protected static final int HLOW = 0;
72
73
74
75
76 protected static final int HHIGH = 1;
77
78
79
80
81 private static final transient Logger logger = Logger
82 .getLogger(AbstractExtendedPyramidIndex.class);
83
84
85
86
87 protected float[] mp;
88
89
90
91
92 protected transient Database cDB;
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public AbstractExtendedPyramidIndex(final File databaseDirectory,
109 final short pivots, PivotSelector < O > pivotSelector, Class<O> type) throws DatabaseException, IOException {
110 super(databaseDirectory, pivots, pivotSelector,type);
111 mp = new float[super.pivotsCount];
112 }
113
114
115
116
117
118
119
120
121
122 @Override
123 protected final void initC() throws DatabaseException {
124 DatabaseConfig dbConfig = createDefaultDatabaseConfig();
125
126 dbConfig.setSortedDuplicates(true);
127 dbConfig.setTransactional(false);
128 cDB = databaseEnvironment.openDatabase(null, "C", dbConfig);
129
130
131
132
133
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @Override
154 protected void calculateIndexParameters() throws DatabaseException,
155 IllegalAccessException, InstantiationException,
156 OutOfRangeException, OBException {
157 long count = super.bDB.count();
158
159 QuantileBin1D[] medianHolder = createMedianHolders(count);
160 Cursor cursor = null;
161 DatabaseEntry foundKey = new DatabaseEntry();
162 DatabaseEntry foundData = new DatabaseEntry();
163
164 try {
165 int i = 0;
166 cursor = bDB.openCursor(null, null);
167 while (cursor.getNext(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
168 assert i == IntegerBinding.entryToInt(foundKey);
169
170 TupleInput in = new TupleInput(foundData.getData());
171 updateMedianHolder(extractTuple(in), medianHolder);
172 i++;
173 }
174 assert i == count;
175
176 } finally {
177 cursor.close();
178 }
179
180 int i = 0;
181 while (i < mp.length) {
182 double median = medianHolder[i].median();
183 assert median >= 0 && median <= 1;
184 mp[i] = (float) median;
185 i++;
186 }
187 logger.debug("Median calculation finished");
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202 protected abstract float[] extractTuple(TupleInput in)
203 throws OutOfRangeException;
204
205
206
207
208
209
210
211
212
213 protected final void updateMedianHolder(final float[] tuple,
214 QuantileBin1D[] medianHolder) {
215 int i = 0;
216 assert tuple.length == medianHolder.length;
217 assert medianHolder.length == pivotsCount;
218 while (i < medianHolder.length) {
219 medianHolder[i].add(tuple[i]);
220 i++;
221 }
222 }
223
224 protected final void updateFloatHolder(final float[] tuple,
225 FloatArrayList[] medianHolder) {
226 int i = 0;
227 assert tuple.length == medianHolder.length;
228 assert medianHolder.length == pivotsCount;
229 while (i < medianHolder.length) {
230 medianHolder[i].add(tuple[i]);
231 i++;
232 }
233 }
234
235
236
237
238
239
240
241
242 protected final QuantileBin1D[] createMedianHolders(final long size) {
243 QuantileBin1D[] res = new QuantileBin1D[pivotsCount];
244 int i = 0;
245 while (i < res.length) {
246
247
248 res[i] = new QuantileBin1D(true, size, 0.00001, 0.00001, 10000,
249 new cern.jet.random.engine.DRand(new java.util.Date()),
250 true, true, 2);
251 i++;
252 }
253 return res;
254 }
255
256 protected final FloatArrayList[] createFloatHolders(int size) {
257 FloatArrayList[] res = new FloatArrayList[pivotsCount];
258 int i = 0;
259 while (i < res.length) {
260
261
262 res[i] = new FloatArrayList(size);
263 i++;
264 }
265 return res;
266 }
267
268
269
270
271
272
273
274
275
276
277 protected final float extendedPyramidNormalization(final float norm,
278 final int i) {
279 return (float) Math.pow(norm, -1.d / (Math.log(mp[i]) / Math.log(2)));
280 }
281
282
283
284
285
286
287
288
289
290
291 protected final float heightOfPoint(final float[] tuple,
292 final int pyramidNumber) {
293 float res = (float) Math.abs(0.5 - tuple[pyramidNumber % pivotsCount]);
294 assert res >= 0 && res <= 0.5;
295 return res;
296 }
297
298
299
300
301
302
303
304 public final float pyramidValue(final float[] tuple) {
305 int pyramid = pyramidOfPoint(tuple);
306 assert pyramid >= 0 && pyramid < pivotsCount * 2 : " Pyramid value:"
307 + pyramid;
308 return pyramid + heightOfPoint(tuple, pyramid);
309 }
310
311
312
313
314
315
316
317 public final int pyramidOfPoint(final float[] tuple) {
318 int jmax = pyramidOfPointAux(tuple);
319 if (tuple[jmax] < 0.5) {
320 return jmax;
321 } else {
322 return jmax + pivotsCount;
323 }
324 }
325
326
327
328
329
330
331
332 protected final int pyramidOfPointAux(final float[] tuple) {
333 int j = 0;
334 assert pivotsCount == tuple.length;
335 while (j < pivotsCount) {
336 int k = 0;
337 boolean failed = false;
338 while (k < pivotsCount && !failed) {
339 if (k == j) {
340 k++;
341 continue;
342 }
343 if (!(Math.abs(0.5 - tuple[j]) >= Math.abs(0.5 - tuple[k]))) {
344
345
346
347 failed = true;
348 }
349 k++;
350 }
351 if (!failed) {
352
353
354 return j;
355 }
356 j++;
357 }
358 assert false : " Catastrophic Failure ";
359 return Integer.MIN_VALUE;
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 protected final boolean intersect(final float[][] q, final int p,
375 float[] minArray, float[] lowHighResult) {
376
377
378 int i = p;
379 assert i < this.pivotsCount * 2;
380 int j = 0;
381 if (i < this.pivotsCount) {
382 float minimum = q[i][MIN];
383 while (j < q.length) {
384 if (j != i) {
385 if (!(minimum <= - minArray[j])) {
386 return false;
387 }
388 }
389 j++;
390 }
391 assert j == pivotsCount;
392 if (q[i][MAX] > 0) {
393 q[i][MAX] = 0;
394 }
395 } else {
396 i = i - this.pivotsCount;
397 float maximum = q[i][MAX] ;
398 while (j < q.length) {
399 if (j != i) {
400 if (! (maximum >= minArray[j])) {
401 return false;
402 }
403 }
404 j++;
405 }
406 assert j == pivotsCount;
407 if (q[i][MIN] < 0) {
408 q[i][MIN] = 0;
409 }
410 }
411
412
413 determineRanges(i, q, lowHighResult);
414 return true;
415 }
416
417
418
419
420
421
422
423 protected final float[] generateMinArray(float[][] query){
424 int i = 0;
425 float [] res = new float[query.length];
426 while(i < query.length){
427 res[i] = min(query[i]);
428 i++;
429 }
430 return res;
431 }
432
433
434
435
436 public int totalBoxes() {
437 return pivotsCount * 2;
438 }
439
440
441
442
443
444
445
446
447
448
449 private final void determineRanges(int p, float[][] q, float[] lowHighResult) {
450
451 int i = p;
452 assert i < pivotsCount;
453 lowHighResult[HHIGH] = max(q[i]);
454 if (isEasyCase(q)) {
455 lowHighResult[HLOW] = 0;
456 } else {
457 int j = 0;
458 float max = 0;
459 while (j < pivotsCount) {
460 if (i != j) {
461 float t = qjmin(q, j, i);
462 if (t > max) {
463 max = t;
464 }
465 }
466 j++;
467 }
468 lowHighResult[HLOW] = max;
469 }
470 }
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509 private final float qjmin(final float[][] q, final int j, final int i) {
510 if (min(q[j]) > min(q[i])) {
511 return min(q[j]);
512 } else {
513 return min(q[i]);
514 }
515 }
516
517
518
519
520
521
522
523
524 private final boolean isEasyCase(final float[][] q) {
525 int i = 0;
526 while (i < q.length) {
527 if (!((q[i][MIN] <= 0) && (0 <= q[i][MAX]))) {
528 return false;
529 }
530 i++;
531 }
532 return true;
533 }
534
535
536
537
538
539
540
541 private final float min(final float[] minMax) {
542 if (minMax[MIN] <= 0 && 0 <= minMax[MAX]) {
543 return 0;
544 } else {
545 return Math.min(Math.abs(minMax[MAX]), Math.abs(minMax[MIN]));
546 }
547 }
548
549
550
551
552
553
554
555 private final float max(final float[] minMax) {
556 return Math.max(Math.abs(minMax[MAX]), Math.abs(minMax[MIN]));
557 }
558
559
560
561
562
563
564
565 protected final void centerQuery(final float[][] q) {
566 int i = 0;
567 while (i < q.length) {
568 q[i][MIN] = q[i][MIN] - 0.5f;
569 q[i][MAX] = q[i][MAX] - 0.5f;
570 i++;
571 }
572 }
573
574
575
576
577
578
579 @Override
580 protected final void closeC() throws DatabaseException {
581 this.cDB.close();
582 }
583
584
585
586
587
588
589
590
591 protected final void copyQuery(final float[][] src, float[][] dest) {
592 int i = 0;
593 while (i < src.length) {
594 dest[i][MIN] = src[i][MIN];
595 dest[i][MAX] = src[i][MAX];
596 i++;
597 }
598 }
599
600 }