-
Notifications
You must be signed in to change notification settings - Fork 4
/
algoB.cc
313 lines (293 loc) · 11.4 KB
/
algoB.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
* Video Quality Assessment Tool using SSIM (VQATS).
* Written by Kah Keng Tay, kahkeng AT gmail DOT com, 2008.
*
* Bidirectional A* algorithm.
*/
#include "vqats.hh"
#include "dtable.hh"
#include "fib.h"
// Macros from http://en.wikipedia.org/wiki/C_preprocessor to prevent side effects
#define min(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a < _b ? _a : _b; })
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
typedef std::pair<frame_t, frame_t> coord_t;
typedef std::set<coord_t> FrontierSet;
enum state_t
{
NONE = 0,
OPEN,
CLOSED
};
struct QueueElement
{
QueueElement(frame_t i1, frame_t i2): _i1(i1), _i2(i2), _estimate(0), _sum(0), _length(0) { }
frame_t _i1, _i2;
score_t _estimate; // estimated score
score_t _sum; // cumulative score
uint16_t _length; // path length
};
static inline int element_comparator(void* x, void* y)
{
QueueElement* a = (QueueElement*)x;
QueueElement* b = (QueueElement*)y;
if (a->_estimate < b->_estimate) return -1;
else if (a->_estimate > b->_estimate) return 1;
else return 0;
}
static inline score_t element_heuristic(frame_t i1, frame_t i2, frame_t j1, frame_t j2)
{
frame_t a1 = abs(i1 - j1);
frame_t a2 = abs(i2 - j2);
if (a1 > a2) return (a1 - a2) * (1.0 - DELETED_FRAME);
else return (a2 - a1) * (1.0 - INSERTED_FRAME);
}
score_t compute_video_score(VQATS& v, const video_t& video1, const video_t& video2)
{
frame_t n1 = v._video_map[video1]._frames.size();
frame_t n2 = v._video_map[video2]._frames.size();
void*** start_he = new_table<void*>(n1 + 1, n2 + 1, NULL); // heap elements
void*** end_he = new_table<void*>(n1 + 1, n2 + 1, NULL); // heap elements
QueueElement*** start_qe = new_table<QueueElement*>(n1 + 1, n2 + 1, NULL); // queue elements
QueueElement*** end_qe = new_table<QueueElement*>(n1 + 1, n2 + 1, NULL); // queue elements
state_t** start_state = new_table<state_t>(n1 + 1, n2 + 1, NONE); // node states
state_t** end_state = new_table<state_t>(n1 + 1, n2 + 1, NONE); // node states
// frontiers
FrontierSet start_frontier;
FrontierSet end_frontier;
start_frontier.insert(coord_t(0, 0));
end_frontier.insert(coord_t(n1, n2));
// initial values
start_qe[0][0] = new QueueElement(0, 0);
end_qe[n1][n2] = new QueueElement(n1, n2);
start_state[0][0] = OPEN;
end_state[n1][n2] = OPEN;
// initial queues
struct fibheap* start_heap = fh_makeheap();
struct fibheap* end_heap = fh_makeheap();
fh_setcmp(start_heap, element_comparator);
fh_setcmp(end_heap, element_comparator);
start_he[0][0] = fh_insert(start_heap, (void*)start_qe[0][0]);
end_he[n1][n2] = fh_insert(end_heap, (void*)end_qe[n1][n2]);
score_t sum = INF;
uint16_t length = 0;
while (true)
{
QueueElement *qs, *qe;
int i1, i2;
score_t s;
// check start frontier
qs = (QueueElement*)fh_extractmin(start_heap);
assert(qs); // there is always a path
assert(start_state[qs->_i1][qs->_i2] == OPEN); // this node should be open
#ifdef DEBUG
printf("extract from start: (%d,%d) est=%.4f sum=%.4f len=%d\n", qs->_i1, qs->_i2, qs->_estimate, qs->_sum, qs->_length);
#endif
start_state[qs->_i1][qs->_i2] = CLOSED;
start_frontier.erase(coord_t(qs->_i1, qs->_i2));
if (end_state[qs->_i1][qs->_i2] == CLOSED) // we have found a path, might not be optimal
{
qe = end_qe[qs->_i1][qs->_i2];
if (qs->_sum + qe->_sum < sum)
{
sum = qs->_sum + qe->_sum;
length = qs->_length + qe->_length;
}
if (qs->_estimate >= sum)
break;
}
// expand this node outward
for (int dir = 0; dir < 3; dir++)
{
switch (dir)
{
case 0: i1 = qs->_i1 + 1; i2 = qs->_i2 + 1; break;
case 1: i1 = qs->_i1; i2 = qs->_i2 + 1; break; // insert frame
case 2: i1 = qs->_i1 + 1; i2 = qs->_i2; break; // delete frame
}
if (i1 <= n1 && i2 <= n2 && start_state[i1][i2] != CLOSED)
{
switch (dir)
{
case 0: s = 1.0 - v.compute_frame_score(video1, video2, i1 - 1, i2 - 1); break;
case 1: s = 1.0 - INSERTED_FRAME; break;
case 2: s = 1.0 - DELETED_FRAME; break;
}
qe = new QueueElement(i1, i2);
qe->_sum = qs->_sum + s;
qe->_length = qs->_length + 1;
// compute heuristic based on other frontier
score_t best_heuristic = element_heuristic(i1, i2, n1, n2), h = 0;
if (end_state[i1][i2] == CLOSED)
{
best_heuristic = end_qe[i1][i2]->_sum;
}
else
{
for (FrontierSet::const_iterator it = end_frontier.begin(); it != end_frontier.end(); ++it)
{
h = element_heuristic(i1, i2, it->first, it->second) + end_qe[it->first][it->second]->_sum;
best_heuristic = min(best_heuristic, h);
}
}
#ifdef DEBUG
printf("best heuristic for (%d,%d) is %.4f\n", i1, i2, best_heuristic);
#endif
qe->_estimate = qe->_sum + best_heuristic;
// extend frontier
start_frontier.insert(coord_t(i1, i2));
switch (start_state[i1][i2])
{
case NONE:
#ifdef DEBUG
printf("expanding start: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qe->_estimate, qe->_sum, qe->_length);
#endif
assert(start_qe[i1][i2] == NULL);
start_he[i1][i2] = fh_insert(start_heap, (void*)qe);
start_qe[i1][i2] = qe;
start_state[i1][i2] = OPEN;
break;
case OPEN:
#ifdef DEBUG
printf("updating start: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qe->_estimate, qe->_sum, qe->_length);
#endif
assert(start_qe[i1][i2] != NULL);
if (qe->_estimate < start_qe[i1][i2]->_estimate)
{
start_qe[i1][i2] = qe;
qe = (QueueElement*)fh_replacedata(start_heap, (struct fibheap_el*)start_he[i1][i2], (void*)qe);
}
delete qe;
break;
default:
assert(false); // should not reach here
break;
}
}
}
// check end frontier
qe = (QueueElement*)fh_extractmin(end_heap);
assert(qe); // there is always a path
assert(end_state[qe->_i1][qe->_i2] == OPEN); // this node should be open
#ifdef DEBUG
printf("extract from end: (%d,%d) est=%.4f sum=%.4f len=%d\n", qe->_i1, qe->_i2, qe->_estimate, qe->_sum, qe->_length);
#endif
end_state[qe->_i1][qe->_i2] = CLOSED;
end_frontier.erase(coord_t(qe->_i1, qe->_i2));
if (start_state[qe->_i1][qe->_i2] == CLOSED) // we have found a path, might not be optimal
{
qs = start_qe[qe->_i1][qe->_i2];
if (qs->_sum + qe->_sum < sum)
{
sum = qs->_sum + qe->_sum;
length = qs->_length + qe->_length;
}
if (qe->_estimate >= sum)
break;
}
// expand this node outward
for (int dir = 0; dir < 3; dir++)
{
switch (dir)
{
case 0: i1 = qe->_i1 - 1; i2 = qe->_i2 - 1; break;
case 1: i1 = qe->_i1; i2 = qe->_i2 - 1; break; // insert frame
case 2: i1 = qe->_i1 - 1; i2 = qe->_i2; break; // delete frame
}
if (i1 >= 0 && i2 >= 0 && end_state[i1][i2] != CLOSED)
{
switch (dir)
{
case 0: s = 1.0 - v.compute_frame_score(video1, video2, i1, i2); break;
case 1: s = 1.0 - INSERTED_FRAME; break;
case 2: s = 1.0 - DELETED_FRAME; break;
}
qs = new QueueElement(i1, i2);
qs->_sum = qe->_sum + s;
qs->_length = qe->_length + 1;
// compute heuristic based on other frontier
score_t best_heuristic = element_heuristic(i1, i2, 0, 0), h = 0;
if (start_state[i1][i2] == CLOSED)
{
best_heuristic = start_qe[i1][i2]->_sum;
}
else
{
for (FrontierSet::const_iterator it = start_frontier.begin(); it != start_frontier.end(); ++it)
{
h = element_heuristic(i1, i2, it->first, it->second) + start_qe[it->first][it->second]->_sum;
best_heuristic = min(best_heuristic, h);
}
}
#ifdef DEBUG
printf("best heuristic for (%d,%d) is %.4f\n", i1, i2, best_heuristic);
#endif
qs->_estimate = qs->_sum + best_heuristic;
// extend frontier
end_frontier.insert(coord_t(i1, i2));
switch (end_state[i1][i2])
{
case NONE:
#ifdef DEBUG
printf("expanding end: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qs->_estimate, qs->_sum, qs->_length);
#endif
assert(end_qe[i1][i2] == NULL);
end_he[i1][i2] = fh_insert(end_heap, (void*)qs);
end_qe[i1][i2] = qs;
end_state[i1][i2] = OPEN;
break;
case OPEN:
#ifdef DEBUG
printf("updating end: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qs->_estimate, qs->_sum, qs->_length);
#endif
assert(end_qe[i1][i2] != NULL);
if (qs->_estimate < end_qe[i1][i2]->_estimate)
{
end_qe[i1][i2] = qs;
qs = (QueueElement*)fh_replacedata(end_heap, (struct fibheap_el*)end_he[i1][i2], (void*)qs);
}
delete qs;
break;
default:
assert(false); // should not reach here
break;
}
}
}
}
assert(length > 0);
#ifdef DEBUG
printf("Sum = %f\n", sum);
printf("Length = %d\n", length);
#endif
#ifdef FH_STATS
printf("MaxN = %d %d\n", fh_maxn(start_heap), fh_maxn(end_heap));
printf("Inserts = %d %d\n", fh_ninserts(start_heap), fh_ninserts(end_heap));
printf("Extracts = %d %d\n", fh_nextracts(start_heap), fh_nextracts(end_heap));
#endif
// clean up
fh_deleteheap(start_heap);
fh_deleteheap(end_heap);
for (uint16_t i1 = 0; i1 <= n1; i1++)
{
for (uint16_t i2 = 0; i2 <= n2; i2++)
{
if (start_qe[i1][i2])
delete start_qe[i1][i2];
if (end_qe[i1][i2])
delete end_qe[i1][i2];
}
}
delete_table(start_he, n1 + 1, n2 + 1);
delete_table(end_he, n1 + 1, n2 + 1);
delete_table(start_qe, n1 + 1, n2 + 1);
delete_table(end_qe, n1 + 1, n2 + 1);
delete_table(start_state, n1 + 1, n2 + 1);
delete_table(end_state, n1 + 1, n2 + 1);
return 1.0 - sum / length;
}