-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSearchAlgorithms.h
242 lines (194 loc) · 6.41 KB
/
SearchAlgorithms.h
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
#pragma once
#include <vector>
#include <omp.h>
#include <array>
namespace SearchAlgorithms
{
constexpr unsigned MAX_THREAD_COUNT = 64;
using Shbool = short; // my reference-able bool
/*
val = 7
sortedVec = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 elements divided to 4 threads => segmSize = 3
Each thread checks if "val" is to their right
T0 T1 T2 T3 RB (Right-Border)
sortedVec = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
isValRght = V V V X X
T2 sees that val is to his right and T3 says it's not, so it shrinks the search interval
=> l = 6, r = 8; => segmSize = 0 => exit while loop
T0 T1 T2
sortedVec = 6 7 8
=> T1 will find the value at index 7
*/
template<typename VecType, typename VecSizeT = std::vector<VecType>::size_type>
VecSizeT ShorterParallelSearch(const std::vector<VecType>& sortedVec, const VecType& val)
{
const unsigned threadCount = omp_get_max_threads();
const unsigned lastThrdID = threadCount - 1;
// each thread will tell if "val" is to their "right"
std::array<Shbool, MAX_THREAD_COUNT+1> isValToTheRight; // + 1 <=> the right border which is just queried by the last thread
isValToTheRight[threadCount] = false; // the right border will say "false" every time
VecSizeT l = 0; // left most index
VecSizeT r = sortedVec.size() - 1; // right most index
VecSizeT indexFound = -1;
#pragma omp parallel \
shared(sortedVec, val, l, r, isValToTheRight, indexFound) \
default(none) // compile error if a local variable is not mentioned in shared(...) or private(...)
{
const unsigned thrdID = omp_get_thread_num();
Shbool& currThrdSaysItsRight = isValToTheRight[thrdID];
const Shbool& nextThrdSaysItsRight = isValToTheRight[thrdID + 1];
while (l <= r - threadCount)
{
const VecSizeT segmSize = (r - l + 1) / (threadCount + 1) + 1;
const VecSizeT currThrdPos = l + segmSize * thrdID;
currThrdSaysItsRight = (sortedVec[currThrdPos] <= val);
// waiting for every thread to finish checking if "val" is on their right
#pragma omp barrier
if (currThrdSaysItsRight != nextThrdSaysItsRight)
{
l = currThrdPos;
if (thrdID != lastThrdID)
r = currThrdPos + segmSize - 1;
}
#pragma omp barrier
}
const VecSizeT currThrdPos = l + thrdID;
if (currThrdPos <= r && sortedVec[currThrdPos] == val)
indexFound = currThrdPos;
}
return indexFound;
}
/* ! In this version, threads look left and there is 1 more segment
val = 8
sortedVec = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 elements divided to (4 threads + 1) segments => segmSize = 3 + 1 = 4
Each thread checks if "val" is to their right and then check the result with their previous thread
LB(LeftBorder) T0 T1 T2 T3
sortedVec = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
isValRght = V V V X X
^ ^
these 2 are different
after the first while:
LB T0 T1 T2 T3
sortedVec = ... 7 8 9 10 ...
isValRght = V V V X X
=> T2 modifies l = 8, r = 8 so "val" must be at the index 8
*/
template<typename VecType, typename VecSizeT = std::vector<VecType>::size_type>
VecSizeT ParallelSearch(const std::vector<VecType>& sortedVec, const VecType& val)
{
const unsigned threadCount = omp_get_max_threads();
const unsigned firstThrdID = 0;
// each thread will tell if "val" is to their "right"
std::array<Shbool, MAX_THREAD_COUNT + 1> isValToTheRight; // + 1 <=> the left border
isValToTheRight[0] = true; // the left border will say "true" every time
std::array<VecSizeT, MAX_THREAD_COUNT> thrdsPos; // position for each thread
VecSizeT l = 0; // left most index
VecSizeT r = sortedVec.size() - 1; // right most index
#pragma omp parallel \
shared(l, r, thrdsPos, isValToTheRight, sortedVec, val) \
default(none) // compile error if a local variable is not mentioned in shared(...) or private(...)
{
const unsigned thrdID = omp_get_thread_num();
VecSizeT& currThrdPos = thrdsPos[thrdID];
Shbool& currThrdSaysItsRight = isValToTheRight[thrdID + 1];
const Shbool& prevThrdSaysItsRight = isValToTheRight[thrdID];
while (l < r)
{
const VecSizeT segmSize = (r - l + 1) / (threadCount + 1) + 1;
currThrdPos = l + segmSize * (thrdID + 1) - 1;
currThrdSaysItsRight = (sortedVec[currThrdPos] <= val);
#pragma omp barrier
if (currThrdSaysItsRight != prevThrdSaysItsRight)
{
r = currThrdPos - 1;
if (thrdID != firstThrdID)
{
l = thrdsPos[thrdID - 1];
}
}
#pragma omp single
{
// no thread looked at this segment so one needs to check whether val is in the last segment
if (isValToTheRight[threadCount])
{
l = thrdsPos[threadCount-1];
}
}
}
}
// now l == r
// if "val" should've been here but it isn't
if (sortedVec[l] != val)
return VecSizeT(-1);
return l;
}
template<typename VecType, typename VecSizeT = std::vector<VecType>::size_type>
VecSizeT BinarySearch(const std::vector<VecType>& sortedVec, VecType val)
{
VecSizeT l = 0, r = sortedVec.size() - 1, m;
while (l < r)
{
m = l + (r - l) / 2 + 1;
if (sortedVec[m] <= val)
{
l = m;
}
else
{
r = m - 1;
}
}
// now l == r
// if "val" should've been here but it isn't
if (sortedVec[l] != val)
return VecSizeT(-1);
return l;
}
template<typename VecType, typename VecSizeT = std::vector<VecType>::size_type>
VecSizeT BinarySearchInParallel(const std::vector<VecType>& sortedVec, const VecType& val)
{
VecSizeT idxFound = -1;
const unsigned threadCount = omp_get_max_threads();
const VecSizeT vecSize = sortedVec.size();
if (vecSize <= threadCount)
{
#pragma omp parallel shared(idxFound)
{
const unsigned thrdID = omp_get_thread_num();
if (thrdID < vecSize && sortedVec[thrdID] == val)
idxFound = thrdID;
}
return idxFound;
}
#pragma omp parallel
{
const unsigned thrdID = omp_get_thread_num();
VecSizeT segmSize = vecSize / threadCount;
VecSizeT l = segmSize * thrdID;
VecSizeT r = segmSize * (thrdID + 1);
if (thrdID == threadCount - 1) // last thread gets a little more work
{
segmSize += vecSize % threadCount;
l = vecSize - segmSize;
r = vecSize - 1;
}
while (l < r)
{
const VecSizeT m = l + (r - l) / 2 + 1;
if (sortedVec[m] <= val)
{
l = m;
}
else
{
r = m - 1;
}
}
if (sortedVec[l] == val)
idxFound = l;
}
return idxFound;
}
}