-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAlgorithm.h
More file actions
235 lines (195 loc) · 6.48 KB
/
Algorithm.h
File metadata and controls
235 lines (195 loc) · 6.48 KB
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
// Contains the main structure of the algorithm
// The actual logic used to solve each query is in AlgoSteps.h
#pragma once
#include "Agarwal.h"
#include "AgarwalProg.h"
#include "EqualTimeDistance.h"
#include "DiHash.h"
#include "Query.h"
#include "CDFQueued.h"
#include "CDFQShortcuts.h"
#include "settings.h"
#include <thread>
#include <chrono>
#include <mutex>
#include <sstream>
#include <iomanip>
#include <iostream>
// All data needed by the algorithm to solve a specific query file
// Also contains structures needed for preprocessing
struct AlgoData {
std::vector<Query> *queries;
std::vector<Trajectory*> *trajectories;
std::vector<std::string> *trajectoryNames;
int numTrajectories;
DiHash* diHash;
FileIO fio;
BoundingBox* boundingBox;
volatile int startedSolving = 0;
volatile int startedSimplifying = 0;
int numWorkers;
};
// Data needed by each worker thread executing the algorithm
// Each thread has seperate algorithm objects so they can use
// their own buffers to store intermediate results.
struct AlgorithmObjects {
std::ostringstream results;
std::vector<Trajectory*> candidates;
BoundingBox bbox;
FileIO fio;
AgarwalSimplification agarwal;
ProgressiveAgarwal agarwalProg;
CDFQueued cdfq;
CDFQShortcuts cdfqs;
};
// TODO: Included here to avoid include problem
#include "AlgoSteps.h"
// Does all needed preprocessing for the given the dataset
void preprocessDataSet(AlgoData *a) {
constructSimplifications(*a);
addPtsToDiHash(*a);
}
// Solves a single query, calls functions in AlgoSteps.h
// Before solving, also loads the query trajectory (since it may
// not be present in the dataset) and constructs simplifications for it.
void solveQuery(AlgoData *a, Query &q, AlgorithmObjects *algo) {
Trajectory *queryTrajectory = algo->fio.parseTrajectoryFile(q.queryTrajectoryFilename, -1);
double diagonal = queryTrajectory->boundingBox->getDiagonal();
makeSourceSimplificationsForTrajectory(*queryTrajectory, *queryTrajectory, diagonal, *algo, numSimplifications);
// for query trajectories, we also simplify the simplifications. Not because we use them directly, but because
// we use their freespace jumps
for (int i = 1; i < numSimplifications; i++) {
makeSourceSimplificationsForTrajectory(*queryTrajectory->simplifications[i], *queryTrajectory, diagonal, *algo, i-1);
}
#if WRITE_OUTPUT_TO_QUERY
std::ostringstream stringStream;
stringStream << "result-" << std::setfill('0') << std::setw(5) << q.queryNumber << ".txt";
std::string filename = stringStream.str();
std::ofstream outfile(filename);
if (!outfile.is_open()) {
std::cout << "Failed to open: " << filename << "\n";
exit(1);
}
#endif
// statistics
int results = 0;
int dihash = 0;
int simp = 0;
int et = 0;
const std::function< void(Trajectory*) >& result = [&](Trajectory *t) -> void{
results++;
#if WRITE_OUTPUT_TO_QUERY
outfile << t->name << "\n";
#endif
};
// the actual pruning steps of the algorithm
collectDiHashPoints(a, q, algo, *queryTrajectory, [&](Trajectory *t) -> void {
//for (Trajectory *t : *a->trajectories) {
dihash++;
pruneWithSimplifications(a, q, algo, *queryTrajectory, t, [&](Trajectory *t) -> void {
simp++;
pruneWithEqualTime(a, q, algo, *queryTrajectory, t, [&](Trajectory *t) -> void {
et++;
pruneWithDecisionFrechet(a, q, algo, *queryTrajectory, t, result);
}, result);
}, result);
//}
});
#if WRITE_OUTPUT_TO_QUERY
outfile.close();
#endif
// TODO: cleanup queryTrajectory, doesn't work from destructor somehow
for (int i = 0; i < queryTrajectory->simplifications.size(); i++) {
Trajectory *s = queryTrajectory->simplifications[i];
for (int j = 0; j < s->simplifications.size(); j++) {
delete s->simplifications[j];
}
delete queryTrajectory->simplifications[i];
}
delete queryTrajectory;
return;
}
// Mutex guarding access to the queryset from the worker threads
std::mutex queryMtx;
// Number of queries allocated to a worker as one 'job'
int querySteps = 20;
// Returns a query index for a worker to solve, locking the query set
int getConcurrentQuery(AlgoData *a) {
queryMtx.lock();
if (a->startedSolving > a->queries->size()) {
queryMtx.unlock();
return -1;
}
int returnQuery = a->startedSolving;
a->startedSolving += querySteps;
queryMtx.unlock();
if (returnQuery % 100 == 0) {
std::cout << " --- Solving: " << returnQuery << "\n";
}
return returnQuery;
}
// Function executed by the worker threads, obtains a query index
// solves a fixed number of queries from that index, then
// tries to obtain a new index. When no queries are left, it exits
// and merges its statistics with the complete statistics.
void worker(AlgoData *a, AlgorithmObjects *algo) {
int current = getConcurrentQuery(a);
std::vector<Query> &queries = *a->queries;
while (current != -1) {
int limit = querySteps;
if (current + querySteps > queries.size()) {
limit = queries.size() - current;
}
for (int step = 0; step < limit; step++) {
Query &c = queries[current + step];
solveQuery(a, c, algo);
}
current = getConcurrentQuery(a);
}
delete algo;
}
void printMS(std::string msg, long ms) {
double timeSec = ms / 1000.0;
std::cout << msg << ": " << timeSec << " sec \n";
}
void print(std::string msg, double value) {
std::cout << msg << ": " << value << "\n";
}
// Datastructure containing worker threads
std::vector<std::thread*> threads;
// Spins up all worker threads, waits for them to complete,
// then prints statistics.
void solveQueries(AlgoData *a) {
for (int i = 0; i < a->numWorkers; i++) {
std::thread *t = new std::thread(worker, a, new AlgorithmObjects());
threads.push_back(t);
}
for (int i = 0; i < a->numWorkers; i++) {
(*threads[i]).join();
delete threads[i];
}
}
void cleanup(AlgoData *a) {
//TODO: improve code by moving deallocations here
//TODO: not strictly necessary because program exits
}
// Entrypoint for the algorithm
void runAlgorithm(AlgoData *a) {
long timeMS = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
std::cout << " - Preprocess\n";
preprocessDataSet(a);
long ptimeMS = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
std::cout << " - Solve\n";
solveQueries(a);
std::cout << " - Cleanup\n";
cleanup(a);
long total = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1) - timeMS;
long totalp = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1) - ptimeMS;
printMS("TOTAL", total);
printMS("TOTAL_SOLVE", totalp);
printMS("PREPROCESSING", total - totalp);
}