diff --git a/defrag/defrag_sim.py b/defrag/defrag_sim.py new file mode 100644 index 0000000..87dd979 --- /dev/null +++ b/defrag/defrag_sim.py @@ -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)) diff --git a/defrag/permutation2.py b/defrag/permutation2.py new file mode 100644 index 0000000..ca71c0f --- /dev/null +++ b/defrag/permutation2.py @@ -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 diff --git a/defrag/permutation_bfs.py b/defrag/permutation_bfs.py new file mode 100644 index 0000000..1391c2e --- /dev/null +++ b/defrag/permutation_bfs.py @@ -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")