-
Notifications
You must be signed in to change notification settings - Fork 594
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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") |