probabilities/mutations20.py

316 lines
9.7 KiB
Python
Raw Normal View History

2023-01-01 23:45:51 +00:00
import numpy as np
import random
import hashlib
import math
def get_state_id(state):
return ','.join([str(x) for x in sorted(state)])
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def id(self):
return ''.join([str(x) for x in self.x])
class Influence():
def __init__(self, a, b):
self.a = a
self.b = b
self.original_dof = set()
self.dof = set()
for i in range(0, len(a.x)):
if a.x[i] != b.x[i]:
self.original_dof.add(i)
self.dof.add(i)
self.coherent = self.a.y == self.b.y
def coherent(self):
return self.a.y == self.b.y
def encode(v):
byte_values = []
for i in range(0, math.ceil(len(v) / 8)):
x = 0
for j in range(0, 8):
index = i * 8 + j
if index >= len(v):
continue
x <<= 1
x |= int(v[index])
byte_values.append(x)
return bytearray(byte_values)
def sha(v):
x = encode(v)
m = hashlib.sha256()
m.update(x)
result = m.digest()
return result[0] & 0b1
def hamming_distance(a, b, flips):
distance = 0
for i in range(0, len(a.x)):
if i in flips:
continue
distance += 1 if a.x[i] != b.x[i] else 0
return distance
def random_x(N):
x = np.zeros((N))
for i in range(0, N):
x[i] = random.randint(0, 1)
return x
def xor(x):
return np.sum(x[16:]) % 2
def create_dof_map(influences):
dof_map = {}
for influence in influences:
for i in influence.dof:
if not i in dof_map:
dof_map[i] = []
dof_map[i].append(influence)
return dof_map
def flip(influences, i):
for influence in influences:
if i in influence.dof:
influence.a.y = int(influence.a.y) ^ 1
def remove_dof(dof_map, i, flip = False):
for influence in dof_map[i]:
influence.dof.remove(i)
if flip:
influence.a.y = int(influence.a.y) ^ 1
# if len(influence.dof) == 0 and not influence.coherent():
# raise Exception('Invalid')
del dof_map[i]
def solve(dof_map, all_influences, all_samples):
eliminated = True
while eliminated:
eliminated = False
for influence in all_influences:
if len(influence.dof) == 1:
i = next(iter(influence.dof))
if influence.coherent:
remove_dof(dof_map, i)
eliminated = True
else:
print('Forced', i)
remove_dof(dof_map, i, True)
eliminated = True
lowest_dof = None
for influence in all_influences:
if not influence.coherent and len(influence.dof) > 1:
if lowest_dof is None or len(influence.dof) < len(lowest_dof.dof):
lowest_dof = influence
flip = None
highest_score = -1
for i in lowest_dof.dof:
per_point_scores = {}
i_influences = dof_map[i]
left = 0
right = 0
for influence in i_influences:
if not influence.a in per_point_scores:
per_point_scores[influence.a] = [0, 0]
if not influence.b in per_point_scores:
per_point_scores[influence.b] = [0, 0]
if influence.coherent:
per_point_scores[influence.a][0] += 1
per_point_scores[influence.b][0] += 1
left += 1
else:
per_point_scores[influence.a][1] += 1
per_point_scores[influence.b][1] += 1
right += 1
print(i, left / (left + right))
num = 0
denom = 0
for _, score in per_point_scores.items():
if score[0] == score[1]:
continue
print(i, score)
num += score[1] / (score[0] + score[1])
denom += 1
score = num / denom if denom > 0 else 0
print(score)
return None
# score_sum = 0
# for j, j_influences in dof_map.items():
# if j in lowest_dof.dof:
# continue
# double_score = 0
# double_totals = [0, 0, 0, 0, 0, 0]
# for influence in i_influences:
# if influence in j_influences:
# weight = 1.0 / ((len(influence.dof) - 2) ** 2)
# if influence.coherent:
# double_score += weight
# double_totals[0] += 1
# else:
# double_score -= weight
# double_totals[3] += 1
# else:
# weight = 1.0 / ((len(influence.dof) - 1) ** 2)
# if influence.coherent:
# double_score -= weight
# double_totals[4] += 1
# else:
# double_score += weight
# double_totals[1] += 1
# for influence in j_influences:
# if influence in i_influences:
# continue
# weight = 1.0 / ((len(influence.dof) - 1) ** 2)
# if influence.coherent:
# double_score -= weight
# double_totals[5] += 1
# else:
# double_score += weight
# double_totals[2] += 1
# score = double_score
# score_sum += score
# # print((i, j), score, single_totals, double_totals)
# if flip is None or score_sum > highest_score:
# highest_score = score_sum
# flip = [i]
# print(i, score_sum)
# if flip is None:
# return None
# print('Chose', flip, 'from', lowest_dof.dof, highest_score)
# for i in flip:
# remove_dof(dof_map, i, True)
# return flip
def main():
N = 32
sample_size = 32
p_dist = np.ones(N)
p_dist.fill(0.5)
epoch = 0
while True:
sample_ids = set()
samples = []
for i in range(0, sample_size):
x = random_x(N)
y = int(sha(x))
p = Point(x, y)
p_id = p.id()
if p_id in sample_ids:
continue
sample_ids.add(p_id)
samples.append(p)
influences = []
for i in range(0, len(samples)):
a = samples[i]
for j in range(i + 1, len(samples)):
b = samples[j]
influences.append(Influence(a, b))
visited = set()
state = []
iterations = 0
while sum([0 if influence.coherent else 1 for influence in influences]) > 0:
# if iterations > 5000:
# state = []
# break
iterations += 1
# print(state)
lowest_dof = None
num_influences = -1
for influence in influences:
if influence.coherent:
continue
if lowest_dof is not None and len(influence.dof) >= num_influences:
continue
has_unvisited_state = False
for i in influence.dof:
state_id = get_state_id(state + [i])
if state_id not in visited:
has_unvisited_state = True
break
if not has_unvisited_state:
continue
if lowest_dof is None or len(influence.dof) < num_influences:
lowest_dof = influence
num_influences = len(influence.dof)
added = False
if lowest_dof is not None:
valid_choices = []
for i in lowest_dof.dof:
state_id = get_state_id(state + [i])
if state_id in visited:
continue
valid_choices.append(i)
if len(valid_choices) > 0:
i = valid_choices[0]
if len(valid_choices) > 1:
p_partial = np.zeros(len(valid_choices))
index = 0
for j in valid_choices:
p_partial[index] = p_dist[j]
np.divide(p_partial, np.sum(p_partial), p_partial)
i = np.random.choice(valid_choices, p=p_partial)
state_id = get_state_id(state + [i])
visited.add(state_id)
state.append(i)
added = True
revert = False
if added:
i = state[-1]
for influence in influences:
if i in influence.dof:
if len(influence.dof) == 1 and influence.coherent:
revert = True
influence.coherent = not influence.coherent
influence.dof.remove(i)
if revert or not added:
if len(state) == 0:
break
i = state.pop(random.randrange(len(state)))
for influence in influences:
if i in influence.original_dof and not i in influence.dof:
influence.coherent = not influence.coherent
influence.dof.add(i)
if len(state) > 0:
epoch += 1
p_dist -= 0.0001 * (sample_size ** 2)
for i in state:
p_dist[i] += 0.0002 * (sample_size ** 2)
# sample_size += 1
print(p_dist)
else:
# sample_size -= 1
pass
if __name__ == "__main__":
main()