-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReachAndMargin.cpp
More file actions
295 lines (242 loc) · 7.73 KB
/
Copy pathReachAndMargin.cpp
File metadata and controls
295 lines (242 loc) · 7.73 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
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
#include "ReachAndMargin.h"
#include <cassert>
#include <iomanip>
void ReachAndMargin::mult(double* dest, const double* one, const double* two) {
for (auto t = 0; t < NFRACS; t++)
dest[t] = one[t] * two[t];
}
void ReachAndMargin::add(double* dest, const double* one, const double* two) {
for (auto t = 0; t < NFRACS; t++)
dest[t] = one[t] + two[t];
}
// stationary probability for the event "reach == r"
double stationaryRho(const unsigned int r, const double adversarialFraction) {
double p = 1 - adversarialFraction;
double beta = (1 - p) / p;
return (1 - beta) * pow(beta, r);
}
// stationary probability for the event "reach >= r"
double stationaryRhoTail(const unsigned int R, const double adversarialFraction) {
double p = 1 - adversarialFraction;
double beta = (1 - p) / p;
return pow(beta, R);
}
// create instances of static const members here (i.e., in the cpp file);
// their values are specified in the class header
const int ReachAndMargin::MAX_COLS;
const int ReachAndMargin::MAX_ROWS;
const int ReachAndMargin::MuZero; // index of the row corresponding to mu = 0
const int ReachAndMargin::TotalCount;
ReachAndMargin::ReachAndMargin(const int N, const int R, const DoubleVector& advFractions)
: N(N), R(R < 0 || R > RMAX ? RMAX : R),
NFRACS(advFractions.size()),
advFractions(advFractions)
{
// set up special matrices
zero = new double[NFRACS];
prDown = new double[NFRACS];
prUp = new double[NFRACS];
for (int i = 0; i < NFRACS; i++) {
zero[i] = 0;
prUp[i] = advFractions[i];
prDown[i] = 1 - prUp[i];
}
// set up temporary matrices
tempA = new double[NFRACS];
tempB = new double[NFRACS];
tempC = new double[NFRACS];
// set up the two main matrices
// one for previous state and the other for current state
memset(matrixOneRaw, 0, sizeof(double) * TotalCount); // current state
memset(matrixTwoRaw, 0, sizeof(double) * TotalCount); // previous state
curMat = matrixOneRaw;
prevMat = matrixTwoRaw;
// time starts at zero
time = 0;
// set initial probabilities
if (R == 0) {
// consider only initial reach = 0
// all mass at (0, 0)
auto cell = get(curMat, 0, 0, 0);
for (int alpha = 0; alpha < NFRACS; alpha++)
cell[alpha] = 1;
}
else {
// consider all initial reach <= R
for (int rho = 0; rho <= R; rho++) {
// considering reach = rho
// relative margin of an empty string equals the reach of the prefix
auto mu = rho;
// grab the cell corresponding to reach = rho
// its value should be the stationary probability of having reach == rho
auto cell = get(curMat, 0, rho, mu);
for (int alpha = 0; alpha < NFRACS; alpha++)
cell[alpha] = stationaryRho(rho, advFractions[alpha]);
}
}
}
ReachAndMargin::~ReachAndMargin()
{
DELETE_ARR(zero);
DELETE_ARR(prDown);
DELETE_ARR(prUp);
DELETE_ARR(tempA);
DELETE_ARR(tempB);
DELETE_ARR(tempC);
}
void ReachAndMargin::swapMat() {
MatrixType temp = prevMat;
prevMat = curMat;
curMat = temp;
}
void ReachAndMargin::calcNewValue(const int r, const int m) {
// initialize to zero
//double* newValue = curMat[r][MuZero + m];
double* newValue = get(curMat, time, r, m);
for (int a = 0; a < NFRACS; a++)
newValue[a] = 0;
//auto diagonallyDown = get(time - 1, r - 1, m - 1);
//auto up = get(time - 1, r, m + 1);
//auto down = get(time - 1, r, m - 1);
//auto left = get(time - 1, r - 1, m);
if (r > 0) {
if (m > 0 || m <= -2) {
// unrestricted
// reach and margin move together
auto diagonallyDown = get(prevMat, time - 1, r - 1, m - 1);
auto diagonallyUp = get(prevMat, time - 1, r + 1, m + 1);
mult(tempA, prUp, diagonallyDown);
mult(tempB, prDown, diagonallyUp);
add(newValue, tempA, tempB);
// *newValue = prUp * diagonallyDown + prDown * diagonallyUp;
}
else if (m == 0) {
// reach positive, margin zero
// up => diagonally up, down => margin stays
auto diagonallyDown = get(prevMat, time - 1, r - 1, m - 1);
auto diagonallyUp = get(prevMat, time - 1, r + 1, m + 1);
auto right = get(prevMat, time - 1, r + 1, m);
add(tempC, diagonallyUp, right);
mult(tempA, prDown, tempC);
mult(tempB, prUp, diagonallyDown);
add(newValue, tempA, tempB);
// *newValue = prDown * (diagonallyUp + right) + prUp * diagonallyDown;
}
else if (m == -1) {
// no incoming down
auto diagonallyDown = get(prevMat, time - 1, r - 1, m - 1);
mult(newValue, prUp, diagonallyDown);
// *newValue = prUp * diagonallyDown;
}
}
else {
// r == 0
if (m == 0) {
// both zero
auto right = get(prevMat, time - 1, r + 1, m);
auto diagonallyUp = get(prevMat, time - 1, r + 1, m + 1);
add(tempA, diagonallyUp, right);
mult(newValue, prDown, tempA);
// *newValue = prDown * (diagonallyUp + right);
}
else if (m == -1) {
// no incoming down
auto up = get(prevMat, time - 1, r, m + 1);
mult(newValue, prDown, up);
// *newValue = prDown * up;
}
else {
// reach zero, margin negative
// up => diagonally up, down => reach stays
auto up = get(prevMat, time - 1, r, m + 1);
auto diagonallyUp = get(prevMat, time - 1, r + 1, m + 1);
add(tempA, diagonallyUp, up);
mult(newValue, prDown, tempA);
// *newValue = prDown * (up + diagonallyUp);
}
}
}
void ReachAndMargin::evolve() {
// prepare for the evolution
time++;
swapMat();
for (int rho = 0; rho <= R + time; rho++) {
int below = -time;
for (int mu = below; mu <= rho; mu++) {
//if (!isValidCoord(time, rho, mu))
// continue;
calcNewValue(rho, mu);
}
}
}
DoubleVector ReachAndMargin::probability(const int minMu) const {
assert(minMu >= -time && minMu <= R + time);
DoubleVector probs(NFRACS, 0);
// chain at the final state
for (int rho = 0; rho <= R + time; rho++) {
for (int mu = minMu; mu <= rho; mu++) {
// these are the cells with nonnegative margin
auto cell = get(curMat, time, rho, mu);
for (int a = 0; a < NFRACS; a++)
probs[a] += cell[a];
}
}
// Now add tail probabilities
if (R != 0)
for (auto a = 0; a < NFRACS; a++)
probs[a] += stationaryRhoTail(R + 1, advFractions[a]);
// Done
return probs;
}
DoubleVector ReachAndMargin::forkableProbability() const {
return probability(0);
}
DoubleVector ReachAndMargin::totalProbability() const {
return probability(-time);
}
bool ReachAndMargin::isValidCoord(const int time, const int rho, const int mu) const {
int below = -time;
bool goodTime = 0 <= time && time <= N;
bool goodRho = 0 <= rho && rho <= (R + time);
bool goodMu = (below <= mu) && (mu <= rho);
return goodTime && goodRho && goodMu;
}
double* ReachAndMargin::get(MatrixType mat, const int time, const int rho, const int mu) const {
if (isValidCoord(time, rho, mu) ) {
// return mat[rho][MuZero + mu];
return &mat[((MuZero + mu) * MAX_COLS + rho) * MAX_FRACS];
}
else
return zero;
}
std::ostream& operator<<(std::ostream& out, const DoubleVector& vec) {
out << "\t";
int n = vec.size();
for (int t = 0; t < n; t++){
if (t > 0)
out << ", ";
out << std::setprecision(12) << vec[t];
}
//out << "\t";
return out;
}
std::ostream& operator<<(std::ostream& out, const ReachAndMargin& self) {
auto M = self.curMat;
out << "=== Matrix at t: " << time << " ===\n";
int below = - self.time;
int above = self.R + self.time;
for (int mu = above; mu >= below; mu--) {
for (int rho = 0; rho <= above; rho++) {
auto cell = self.get(self.curMat, self.time, rho, mu);
out << "[";
for (int a = 0; a < self.NFRACS; a++) {
if (a > 0)
out << ", ";
out << std::setw(8) << cell[a];
}
out << "]";
}
out << "\t" << std::endl;
}
return out;
}