-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path541_v2.py
145 lines (131 loc) · 3.07 KB
/
541_v2.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
from fractions import Fraction
def extendedEuclidean(a,n):
t = 0
r = n
newt = 1
newr = a
while newr!=0:
quotient = r/newr
t,newt = newt, t - quotient * newt
r,newr = newr, r - quotient * newr
if r>1:
return -1
if t<0:
t = t+n
return t
def getModInverses(p,upper):
mod_inverses = []
for n in range(0,upper):
mod_inverses.append(extendedEuclidean(n,upper))
return mod_inverses
# Example: HStar(294,299,7) gives 295,296,297,298,299
def HStar(lower,upper,p):
frac = Fraction(0)
for i in range(lower+1,upper+1):
if i%p!=0:
frac += Fraction(1,i)
return frac
# Example: isReducible(299,7,2) gives 294.
# Example: isReducible(49,7,2) gives 49
def isReducible(n,p,power):
if n<p**power:
return -1
else:
quotient = n//p**power
return quotient*p**power
def H(n,nbar,p,power,last_memo):
right_term = memoize[nbar]*Fraction(1,p)
lower = isReducible(n,p,power)
if lower==-1:
left_term = hstar_memoize[last_memo] + HStar(last_memo,n,p)
hstar_memoize[n] = left_term
else:
left_term = HStar(lower,n,p)
return left_term+right_term
def fractionToModP(frac,p):
numerator = frac.numerator % p
denominator = frac.denominator % p
inv = mod_inverses[denominator]
if denominator==0:
return -1
else:
return (numerator*inv)%p
def getCongruences(p):
congruences = {}
for i in range(p):
index = fractionToModP(harmonic_sums[i],p)
if index not in congruences:
congruences[index] = [i]
else:
congruences[index].append(i)
return congruences
def getHarmonicSums(p):
harmonic_sums = []
harmonic_sums.append(Fraction(0))
for i in range(1,p):
harmonic_sums.append(Fraction(1,i)+harmonic_sums[-1])
return harmonic_sums
def getPsi(frac,p):
frac*=Fraction(1,p)
return fractionToModP(frac,p)
def DFS(n,nbar,p,depth,last_memo):
print n,depth
memoize[n] = H(n,nbar,p,depth,last_memo)
last_memo = n
psi = getPsi(memoize[n],p)
try:
r_vals = congruences[(p-psi)%p]
except KeyError:
return 0
for i in r_vals:
new = n*p + i
J.append(new)
DFS(new,n,p,depth-1)
def BFS(FIFO):
last = 0
while (len(FIFO)!=0):
node = FIFO.pop(0)
n, nbar, p, depth = node.n, node.nbar, node.p, node.depth
memoize[n] = H(n,nbar,p,depth,last)
last = n
psi = getPsi(memoize[n],p)
print node, psi
try:
r_vals = congruences[(p-psi)%p]
for i in r_vals:
new = n*p + i
node = Node(new,n,p,depth-1,last)
J.append(new)
FIFO.append(node)
except KeyError:
pass
class Node:
def __init__ (self,n,nbar,p,depth,last):
self.n = n
self.nbar = nbar
self.p = p
self.depth = depth
self.last = last
def __str__ (self):
return "n:%d, nBar:%d, p:%d, depth:%d, last:%d" % (self.n,self.nbar,self.p,self.depth,self.last)
J = [0]
memoize = {0:0}
hstar_memoize = {0:0}
last = 0
p = 137
depth = 8
harmonic_sums = getHarmonicSums(p)
print "Populating Mod Inverses..."
mod_inverses = getModInverses(p,p)
congruences = getCongruences(p)
FIFO = []
for i in range(1,len(harmonic_sums)):
if harmonic_sums[i].numerator%p==0:
node = Node(i,0,p,depth,last)
J.append(i)
FIFO.append(node)
# DFS(i,0,p,depth,last_memo)
BFS(FIFO)
J = sorted(J)
print J
print J[-1]*p + p-1