This repository has been archived by the owner on Dec 6, 2023. It is now read-only.
forked from saad0105050/PoS-visualization
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrelative_margin.py
161 lines (128 loc) · 3.29 KB
/
relative_margin.py
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
# # recursive definition of reach
# # last_slot = 1, 2, ...
# def reach(w, slot = None):
# if w == "" or w is None:
# return 0
# if slot is None:
# slot = len(w)
# if slot == 0:
# return 0
# prev_reach = reach(w, slot - 1)
# bit = w[slot - 1]
# if bit == "1":
# return prev_reach + 1
# # honest bit
# if prev_reach == 0:
# return 0
# else:
# return prev_reach - 1
# # recursive definition of margin
# def margin(w, x_len = 0, slot = None):
# if w == "" or w is None:
# return 0
# if slot is None:
# slot = len(w)
# if slot == x_len:
# return reach(w, x_len)
# prev_reach = reach(w, slot - 1)
# prev_margin = margin(w, slot - 1)
# bit = w[slot - 1]
# if bit == "1":
# return prev_margin + 1
# else:
# # honest bit
# if prev_margin == 0 and prev_reach > 0:
# return 0
# else:
# return prev_margin - 1
def reach_and_margin(w, x_len = None, reach = None):
if w is None or w == "":
return [], []
if x_len is None or x_len < 0:
x_len = 0
n = len(w)
if reach is None:
reach = [0] * (n + 1) # plus one for the genesis slot
for i in range(n + 1):
# calc reach
if i == 0:
reach[i] = 0 # the base case
else:
bit = w[i - 1]
if bit == "1":
reach[i] = reach[i-1] + 1
else:
if reach[i-1] == 0:
reach[i] = 0
else:
reach[i] = reach[i-1] - 1
assert len(reach) == (n+1)
assert x_len <= n
y_len = n - x_len
margin = [0] * (y_len + 1) # plus one for the base case (empty y)
for i in range(x_len, n + 1):
bit = w[i - 1]
# calc relative margin
j = i - x_len
if j == 0:
margin[j] = reach[x_len] # the base case
else:
if bit == "1":
margin[j] = margin[j-1] + 1
else:
if margin[j-1] == 0 and reach[i - 1] > 0:
margin[j] = 0
else:
margin[j] = margin[j-1] - 1
return reach, margin
# the returned array includes the value at the starting position
def partial_sum_min(w):
if w is None or w == "":
return [], []
n = len(w)
psum = [0] * (n+1)
pmin = [0] * (n+1)
# initial values
for i in range(n):
if w[i] == "1":
move = 1
else:
move = -1
psum[i+1] = psum[i] + move
pmin[i+1] = min(pmin[i], psum[i+1])
return psum, pmin
def left_catalan_slots(w):
if w is None or w == "":
return []
lcat = []
n = len(w)
psum, pmin = partial_sum_min(w)
for i in range(n):
slot = i + 1
if w[i] == "0" and psum[slot] == pmin[slot] and pmin[slot] < pmin[slot - 1]:
lcat.append(slot)
return lcat
def right_catalan_slots(w):
if w is None or w == "":
return []
rcat = []
n = len(w)
psum, pmin = partial_sum_min(w)
r_psum, r_pmin = partial_sum_min("".join(reversed(w)))
# print("w: {}\nr_w: {}".format(w, w[::-1]))
# print("psum: {}\nr_psum: {}".format(psum, r_psum))
# print("pmin: {}\nr_pmin: {}".format(pmin, r_pmin))
for i in range(n):
slot = i + 1
r_slot = n + 1 - slot
# r_slot = slot
if w[i] == "0" and r_psum[r_slot] == r_pmin[r_slot] and r_pmin[r_slot] < r_pmin[r_slot - 1]:
rcat.append(slot)
return rcat
def catalan_slots(w):
if w is None or w == "":
return []
lcat = left_catalan_slots(w)
rcat = right_catalan_slots(w)
cat = set(lcat).intersection(rcat)
return sorted(list(cat))