Added defragmentation-related stuff

This commit is contained in:
Vitalik Buterin 2018-09-24 10:52:49 -04:00
parent fca55f589b
commit c5edaabaff
3 changed files with 197 additions and 0 deletions

83
defrag/defrag_sim.py Normal file
View File

@ -0,0 +1,83 @@
import random, math
def mk_initial_balances(accts, coins):
o = []
for i in range(accts):
o.extend([i] * random.randrange((coins - len(o)) * 2 // (accts - i)))
o.extend([accts-1] * (coins - len(o)))
return o
def fragments(coins):
o = 0
for i in range(1, len(coins)):
if coins[i] != coins[i-1]:
o += 1
return o
def xfer(coins, frm, to, value):
coins = coins[::]
pos = 0
while pos < len(coins) and value > 0:
if coins[pos] == frm:
coins[pos] = to
value -= 1
pos += 1
return coins
def unscramble(coins, c1, c2):
coins = coins[::]
k1 = coins.count(c1)
pos = 0
while pos < len(coins):
if coins[pos] in (c1, c2):
coins[pos] = c1 if k1 > 0 else c2
if coins[pos] == c1:
k1 -= 1
pos += 1
return coins
def multi_unscramble(coins, addrs):
coins = coins[::]
ks = [coins.count(c) for c in addrs]
pos = 0
at = 0
while pos < len(coins):
if coins[pos] in addrs:
coins[pos] = addrs[at]
ks[at] -= 1
if ks[at] == 0:
at += 1
pos += 1
return coins
def unscramble_swap_strategy(coins, rounds):
for i in range(rounds):
c1, c2 = sorted([random.randrange(max(coins)+1) for _ in range(2)])
coins = unscramble(coins, c1, c2)
return coins
def run_with_unscrambling(coins, rounds):
M = max(coins) + 1
for i in range(rounds):
c1, c2 = [random.randrange(M) for _ in range(2)]
value = int(coins.count(c1) ** random.random())
coins = xfer(coins, c1, c2, value)
coins = unscramble(coins, min(c1, c2), max(c1, c2))
return coins
def run_with_unscramble_online(coins, rounds):
M = max(coins) + 1
for i in range(rounds):
c1, c2 = [random.randrange(M) for _ in range(2)]
value = int(coins.count(c1) ** random.random())
coins = xfer(coins, c1, c2, value)
if random.random() < 1:
cx = sorted([random.randrange(M) for _ in range(5)])
coins = multi_unscramble(coins, cx)
return coins
c = mk_initial_balances(200, 10000)
# random.shuffle(c)
# c = unscramble_swap_strategy(c, 20000)
c = run_with_unscramble_online(c, 10000)
print(fragments(c))

49
defrag/permutation2.py Normal file
View File

@ -0,0 +1,49 @@
import random
def mk_shuffle(n):
L = list(range(n))
random.shuffle(L)
return L
def mk_fragmented_shuffle(n, shuffs):
L = list(range(n))
for i in range(shuffs):
x1 = random.randrange(n)
x2 = random.randrange(n)
value = int(min(n - x1, n - x2, abs(x2 - x1)) ** random.random())
L[x1:x1+value], L[x2:x2+value] = L[x2:x2+value], L[x1:x1+value]
return L
def fragments(vals):
tot = 1
for i in range(1, len(vals)):
if vals[i] != vals[i-1] + 1:
tot += 1
return tot
def apply_perm(vals, perm):
o = [0 for x in vals]
for i in range(len(perm)):
o[i] = vals[perm[i]]
return o
def attempt_fix(vals):
perm = list(range(len(vals)))
indices = {}
for i, x in enumerate(vals):
indices[x] = i
for i in range(len(vals)):
if perm[i] == i and vals[i] != i:
poz = indices[i]
if perm[poz] == poz:
perm[i], perm[poz] = perm[poz], perm[i]
assert apply_perm(perm, perm) == list(range(len(vals)))
return perm
def fix(vals):
goal = list(range(len(vals)))
path = []
while vals != goal:
vals = apply_perm(vals, attempt_fix(vals))
path.append(vals)
return path

65
defrag/permutation_bfs.py Normal file
View File

@ -0,0 +1,65 @@
import heapq, random
def distance_score(state):
state = [int(x) for x in state.split(',')]
tot = 0
for i, s in enumerate(state):
xorval = (i+1) ^ s
indexmask = 1
while indexmask < len(state):
if xorval & indexmask:
tot += 1
indexmask <<= 1
return tot
def generate_legal_moves_for_bit(state, bit):
o = set()
xormask = 2**bit
state = [int(x) for x in state.split(',')]
for i in range(2**(len(state)-1)):
new_state = state[::]
indexmask = 1
for j in range(len(state)):
if j > (j ^ xormask):
if i & indexmask:
new_state[j], new_state[j ^ xormask] = new_state[j ^ xormask], new_state[j]
indexmask <<= 1
o.add(','.join([str(x) for x in new_state]))
return o
def generate_legal_moves(state):
o = set()
b = 0
while 2**b < len(state):
o = o.union(generate_legal_moves_for_bit(state, b))
b += 1
return o
def mk_shuffle(n):
L = list(range(1, n+1))
random.shuffle(L)
return ','.join([str(x) for x in L])
def find_path(start):
parents = {}
scores = {start: 0}
queue = [(distance_score(start), start)]
goal = ','.join([str(x) for x in sorted([int(x) for x in start.split(',')])])
totvs = 0
while len(queue):
qval = heapq.heappop(queue)[1]
newvals = [x for x in generate_legal_moves(qval) if x not in scores]
for v in newvals:
if scores.get(v, 99999) > scores[qval] + 1:
scores[v] = scores[qval] + 1
parents[v] = qval
totvs += 1
if v == goal:
path = [v]
while path[-1] != start:
parent = parents[path[-1]]
path.append(parent)
return path
for v in newvals:
heapq.heappush(queue, (distance_score(v), v))
raise Exception("huh")