import numpy as np
from scipy.optimize import minimize
import mpmath as mp
from mpmath import mpf
import scipy
m = 16 #m parameter from paper
mp.dps = 500 #This will force mpmath to use a precision of
#500 bits/double, just as a sanity check
def stable_qtk(x):
#The function (1-e^(-x))/x is highly unstable for small x, so we will
# Lower bound it using the summation in Equation 13 in the paper
ans = 0
for beta in range(30):
ans += mp.exp(-x) * x**beta / mp.factorial(beta) * 1/(beta+1)
return ans
#Computes f_j(alphas, alphat) in time O(m^2)
def fj(j, alphas, alphat):
part1 = 0
for k in range(1, j): #Goes from 1 to j-1 as in paper
part1 += 1/m * (1-alphas[k])
#alphas_hat[nu]=alphas[nu] if nu<=j-1 and alphat if nu==j
alphas_hat = [alphas[nu] for nu in range(j)] + [alphat]
part2 = 0
for k in range(j, m+1): #Goes from j to m as in paper
product = 1
for nu in range(1, k): #Goes from 1 to k-1
product *= (alphas[nu]**(1/m))
wk = 0
s_nu = 0
for nu in range(j): #from 0 to j-1
r_nu = (m-(k-1)+nu)/m * mp.log(alphas_hat[nu]/alphas_hat[nu+1])
wk += mp.exp(-s_nu)*(1-mp.exp(-r_nu)) * 1/(m-(k-1)+nu)
s_nu += r_nu
q_t_k = stable_qtk( 1/m * mp.log(alphat/alphas[k]) )
part2 += product * wk * q_t_k
return part1 + part2
def evaluate_competitive_ratio(alphas):
assert np.isclose(np.float64(alphas[0]), 1) #first should be 1
assert np.isclose(np.float64(alphas[-1]), 0) #Last should be 0
assert len(alphas)==(m+2)
competitive_ratio = 1
for j in range(1, m+2): #Goes from 1 to m+1 as in paper
#Avoid precision errors when alphat~~1, subtract 1e-8
alphat_bounds = [(np.float64(alphas[j]),np.float64(min(alphas[j-1], 1-1e-8)))]
x0 = [np.float64((alphas[j]+alphas[j-1])/2)]
res = minimize(lambda alphat: fj(j, alphas, alphat[0])/(1-alphat[0]),
x0=x0,
bounds=alphat_bounds)
"""
As a sanity check, we will evaluate fj(alphas, x)/(1-x) for x in alphat_bounds
and assert that res.fun (the minimum value we got) is <= fj(alphas, x)/(1-x).
This is just a sanity check to increase the confidence that the minimizer
actually got the right minimum
"""
trials = np.linspace(alphat_bounds[0][0], alphat_bounds[0][1], 30) #30 breaks
min_in_trials = min([ fj(j, alphas, x)/(1-x) for x in trials ])
assert res.fun <= min_in_trials
"""
End of sanity check
"""
competitive_ratio = min(competitive_ratio, res.fun)
return competitive_ratio
alphas = [mpf('1.0'), mpf('0.66758603836404173'), mpf('0.62053145929311715'),
mpf('0.57324846512425975'),
mpf('0.52577742556626594'), mpf('0.47816906417879007'), mpf('0.43049233470891257'),
mpf('0.38283722646593055'), mpf('0.33533950489086961'), mpf('0.28831226925828957'),
mpf('0.23273108361807243'), mpf('0.19315610994691487'), mpf('0.16547915613363387'),
mpf('0.13558301500280728'), mpf('0.10412501367635961'), mpf('0.071479537771643828'),
mpf('0.036291830527618585'), mpf('0.0')]
c = evaluate_competitive_ratio(alphas)
print(c)
aW1wb3J0IG51bXB5IGFzIG5wCmZyb20gc2NpcHkub3B0aW1pemUgaW1wb3J0IG1pbmltaXplCmltcG9ydCBtcG1hdGggYXMgbXAKZnJvbSBtcG1hdGggaW1wb3J0IG1wZgppbXBvcnQgc2NpcHkKCgoKbSA9IDE2ICNtIHBhcmFtZXRlciBmcm9tIHBhcGVyCm1wLmRwcyA9IDUwMCAjVGhpcyB3aWxsIGZvcmNlIG1wbWF0aCB0byB1c2UgYSBwcmVjaXNpb24gb2YgCiAgICAgICAgICAgICAjNTAwIGJpdHMvZG91YmxlLCBqdXN0IGFzIGEgc2FuaXR5IGNoZWNrCgoKZGVmIHN0YWJsZV9xdGsoeCk6CiAgICAjVGhlIGZ1bmN0aW9uICgxLWVeKC14KSkveCBpcyBoaWdobHkgdW5zdGFibGUgZm9yIHNtYWxsIHgsIHNvIHdlIHdpbGwgCiAgICAjIExvd2VyIGJvdW5kIGl0IHVzaW5nIHRoZSBzdW1tYXRpb24gaW4gRXF1YXRpb24gMTMgaW4gdGhlIHBhcGVyCiAgICBhbnMgPSAwCiAgICBmb3IgYmV0YSBpbiByYW5nZSgzMCk6CiAgICAgICAgYW5zICs9IG1wLmV4cCgteCkgKiB4KipiZXRhIC8gbXAuZmFjdG9yaWFsKGJldGEpICogMS8oYmV0YSsxKQogICAgcmV0dXJuIGFucwoKICAgIAogICAgCiNDb21wdXRlcyBmX2ooYWxwaGFzLCBhbHBoYXQpIGluIHRpbWUgTyhtXjIpCmRlZiBmaihqLCBhbHBoYXMsIGFscGhhdCk6CiAgICBwYXJ0MSA9IDAKICAgIGZvciBrIGluIHJhbmdlKDEsIGopOiAjR29lcyBmcm9tIDEgdG8gai0xIGFzIGluIHBhcGVyCiAgICAgICAgcGFydDEgKz0gMS9tICogKDEtYWxwaGFzW2tdKQogICAgCiAgICAjYWxwaGFzX2hhdFtudV09YWxwaGFzW251XSBpZiBudTw9ai0xIGFuZCBhbHBoYXQgaWYgbnU9PWoKICAgIGFscGhhc19oYXQgPSBbYWxwaGFzW251XSBmb3IgbnUgaW4gcmFuZ2UoaildICsgW2FscGhhdF0gICAgCiAgICBwYXJ0MiA9IDAKICAgIGZvciBrIGluIHJhbmdlKGosIG0rMSk6ICNHb2VzIGZyb20gaiB0byBtIGFzIGluIHBhcGVyCiAgICAgICAgcHJvZHVjdCA9IDEKICAgICAgICBmb3IgbnUgaW4gcmFuZ2UoMSwgayk6ICNHb2VzIGZyb20gMSB0byBrLTEKICAgICAgICAgICAgcHJvZHVjdCAqPSAoYWxwaGFzW251XSoqKDEvbSkpCiAgICAgICAgCiAgICAgICAgd2sgPSAwCiAgICAgICAgc19udSA9IDAKICAgICAgICBmb3IgbnUgaW4gcmFuZ2Uoaik6ICNmcm9tIDAgdG8gai0xCiAgICAgICAgICAgIHJfbnUgPSAobS0oay0xKStudSkvbSAqIG1wLmxvZyhhbHBoYXNfaGF0W251XS9hbHBoYXNfaGF0W251KzFdKQogICAgICAgICAgICB3ayArPSBtcC5leHAoLXNfbnUpKigxLW1wLmV4cCgtcl9udSkpICogMS8obS0oay0xKStudSkKICAgICAgICAgICAgc19udSArPSByX251CiAgICAgICAgICAgIAogICAgICAgIHFfdF9rID0gc3RhYmxlX3F0ayggMS9tICogbXAubG9nKGFscGhhdC9hbHBoYXNba10pICkKICAgICAgICBwYXJ0MiArPSBwcm9kdWN0ICogd2sgKiBxX3RfawogICAgCiAgICByZXR1cm4gcGFydDEgKyBwYXJ0MgogICAgICAgIAoKZGVmIGV2YWx1YXRlX2NvbXBldGl0aXZlX3JhdGlvKGFscGhhcyk6CiAgICBhc3NlcnQgbnAuaXNjbG9zZShucC5mbG9hdDY0KGFscGhhc1swXSksIDEpICNmaXJzdCBzaG91bGQgYmUgMQogICAgYXNzZXJ0IG5wLmlzY2xvc2UobnAuZmxvYXQ2NChhbHBoYXNbLTFdKSwgMCkgI0xhc3Qgc2hvdWxkIGJlIDAKICAgIGFzc2VydCBsZW4oYWxwaGFzKT09KG0rMikKICAgIAogICAgY29tcGV0aXRpdmVfcmF0aW8gPSAxCiAgICAKICAgIGZvciBqIGluIHJhbmdlKDEsIG0rMik6ICNHb2VzIGZyb20gMSB0byBtKzEgYXMgaW4gcGFwZXIKICAgICAgICAjQXZvaWQgcHJlY2lzaW9uIGVycm9ycyAgd2hlbiBhbHBoYXR+fjEsIHN1YnRyYWN0IDFlLTgKICAgICAgICBhbHBoYXRfYm91bmRzID0gWyhucC5mbG9hdDY0KGFscGhhc1tqXSksbnAuZmxvYXQ2NChtaW4oYWxwaGFzW2otMV0sIDEtMWUtOCkpKV0gCiAgICAgICAgCiAgICAgICAgeDAgPSBbbnAuZmxvYXQ2NCgoYWxwaGFzW2pdK2FscGhhc1tqLTFdKS8yKV0KICAgICAgICByZXMgPSBtaW5pbWl6ZShsYW1iZGEgYWxwaGF0OiBmaihqLCBhbHBoYXMsIGFscGhhdFswXSkvKDEtYWxwaGF0WzBdKSwgCiAgICAgICAgICAgICAgICAgICAgICAgeDA9eDAsIAogICAgICAgICAgICAgICAgICAgICAgIGJvdW5kcz1hbHBoYXRfYm91bmRzKQogICAgICAgICIiIgogICAgICAgIEFzIGEgc2FuaXR5IGNoZWNrLCB3ZSB3aWxsIGV2YWx1YXRlIGZqKGFscGhhcywgeCkvKDEteCkgZm9yIHggaW4gYWxwaGF0X2JvdW5kcwogICAgICAgIGFuZCBhc3NlcnQgdGhhdCByZXMuZnVuICh0aGUgbWluaW11bSB2YWx1ZSB3ZSBnb3QpIGlzIDw9IGZqKGFscGhhcywgeCkvKDEteCkuIAogICAgICAgIFRoaXMgaXMganVzdCBhIHNhbml0eSBjaGVjayB0byBpbmNyZWFzZSB0aGUgY29uZmlkZW5jZSB0aGF0IHRoZSBtaW5pbWl6ZXIgCiAgICAgICAgYWN0dWFsbHkgZ290IHRoZSByaWdodCBtaW5pbXVtCiAgICAgICAgIiIiCiAgICAgICAgdHJpYWxzID0gbnAubGluc3BhY2UoYWxwaGF0X2JvdW5kc1swXVswXSwgYWxwaGF0X2JvdW5kc1swXVsxXSwgMzApICMzMCBicmVha3MgCiAgICAgICAgbWluX2luX3RyaWFscyA9IG1pbihbIGZqKGosIGFscGhhcywgeCkvKDEteCkgZm9yIHggaW4gdHJpYWxzIF0pCiAgICAgICAgYXNzZXJ0IHJlcy5mdW4gPD0gbWluX2luX3RyaWFscwogICAgICAgICIiIgogICAgICAgIEVuZCBvZiBzYW5pdHkgY2hlY2sKICAgICAgICAiIiIKICAgICAgICBjb21wZXRpdGl2ZV9yYXRpbyA9IG1pbihjb21wZXRpdGl2ZV9yYXRpbywgcmVzLmZ1bikKICAgIAogICAgcmV0dXJuIGNvbXBldGl0aXZlX3JhdGlvCiAgICAKICAgIAphbHBoYXMgPSBbbXBmKCcxLjAnKSwgbXBmKCcwLjY2NzU4NjAzODM2NDA0MTczJyksIG1wZignMC42MjA1MzE0NTkyOTMxMTcxNScpLCAKbXBmKCcwLjU3MzI0ODQ2NTEyNDI1OTc1JyksCiBtcGYoJzAuNTI1Nzc3NDI1NTY2MjY1OTQnKSwgbXBmKCcwLjQ3ODE2OTA2NDE3ODc5MDA3JyksIG1wZignMC40MzA0OTIzMzQ3MDg5MTI1NycpLAogbXBmKCcwLjM4MjgzNzIyNjQ2NTkzMDU1JyksIG1wZignMC4zMzUzMzk1MDQ4OTA4Njk2MScpLCBtcGYoJzAuMjg4MzEyMjY5MjU4Mjg5NTcnKSwKIG1wZignMC4yMzI3MzEwODM2MTgwNzI0MycpLCBtcGYoJzAuMTkzMTU2MTA5OTQ2OTE0ODcnKSwgbXBmKCcwLjE2NTQ3OTE1NjEzMzYzMzg3JyksCiBtcGYoJzAuMTM1NTgzMDE1MDAyODA3MjgnKSwgbXBmKCcwLjEwNDEyNTAxMzY3NjM1OTYxJyksIG1wZignMC4wNzE0Nzk1Mzc3NzE2NDM4MjgnKSwKIG1wZignMC4wMzYyOTE4MzA1Mjc2MTg1ODUnKSwgbXBmKCcwLjAnKV0KYyA9IGV2YWx1YXRlX2NvbXBldGl0aXZlX3JhdGlvKGFscGhhcykKcHJpbnQoYykK