-
Notifications
You must be signed in to change notification settings - Fork 0
/
Algorithm.py
124 lines (88 loc) · 4.18 KB
/
Algorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import Player as p
import copy
import Node as nn
import math, random
class Algorithm():
def __init__(self, size, negativeEffectBias, positiveBias, positiveEffectBias, similarityWeight):
self.nodeLikelihoods = [1] * size
# self.percentSamplesAlloted = 0.2
# self.percentTracesAlloted = 0.05
self.negativeEffectBias = negativeEffectBias
self.positiveBias = positiveBias
self.positiveEffectBias = positiveEffectBias
self.similarityWeight = similarityWeight
def InitialScan(self, nodes):
# All negative nodes can't be patient zero, and the chances
# of their neighbors being patient zero is less.
for node in nodes:
if node.state == 0:
self.nodeLikelihoods[node.id] = 0
for neighbor in node.connections:
self.nodeLikelihoods[neighbor.id] -= self.negativeEffectBias
elif node.state == 1:
self.nodeLikelihoods[node.id] += self.positiveBias
for neighbor in node.connections:
self.nodeLikelihoods[neighbor.id] += self.positiveEffectBias
def ChooseOneToSample(self, player):
# Find most likely after initial scan
self.InitialScan(player.nodes.values())
save = []
for node in player.sampled:
save.append((player.nodes[node].id, self.nodeLikelihoods[node]))
self.nodeLikelihoods[node] = -999
mostLikely = max(self.nodeLikelihoods)
for Id, likelihood in save:
self.nodeLikelihoods[Id] = likelihood
# Find most likely nodes and sample them
likelyNodes = []
for node in player.nodes.values():
if self.nodeLikelihoods[node.id] == mostLikely:
likelyNodes.append(node.id)
return random.choice(likelyNodes)
def FindDifference(self, list1, list2):
# Calculate Jaccard similarity
intersection = len(set(list1).intersection(set(list2)))
union = len(set(list1).union(set(list2)))
jaccard_similarity = intersection / union
return jaccard_similarity
def TraceSpreadPattern(self, Player, target_node):
new_player = copy.deepcopy(Player)
# Reset infections
for node in new_player.nodes.values():
node.state = 0
nn.runInfectionSimulation(4, new_player.nodes, selected_p_zero=new_player.nodes[target_node+1])
infectionsForNewPlayer = [node.state for node in new_player.nodes.values()]
infectionsForCurrentPlayer = [node.state for node in Player.nodes.values()]
difference = math.fabs(self.FindDifference(infectionsForNewPlayer, infectionsForCurrentPlayer))
self.nodeLikelihoods[int(Player.nodes[target_node+1].id) - 1] -= (difference * self.similarityWeight)
def getSortedIds(self):
indexed_arr = [(value, index) for index, value in enumerate(self.nodeLikelihoods)]
# Sort the list of tuples based on values
sorted_arr = sorted(indexed_arr, key=lambda x: x[0])
# Extract the sorted indices
sorted_indices = [index for _, index in sorted_arr]
return sorted_indices
def run_ai(ai, player, percentSamples, percentTraced):
numSamples = round(percentSamples * player.size)
numTraced = round(percentTraced * numSamples)
numberToSelect = math.ceil(0.03 * player.size)
for _ in range(numSamples):
chosen = ai.ChooseOneToSample(player)
player.sample(chosen)
print(f"Sampled {len(player.sampled)} Nodes: {player.sampled}")
# After, calculate likelihoods
sorted_indices = ai.getSortedIds()
# Find spread pattern for most likely
for Id in sorted_indices[:numTraced]:
ai.TraceSpreadPattern(player, Id)
traced = sorted_indices[:numTraced]
print(f"Traced Spread Patterns For {sorted_indices[:numTraced]}")
# Compare likelihoods again
sorted_indices = ai.getSortedIds()
# Print 5 Top Choices (rightmost is the one it's most confident in)
print(
f"Top Choices From AI (least confident to most confident, right being most confident): \n{sorted_indices[-numberToSelect:]}"
)
for nodeNumber in sorted_indices[-numberToSelect:]:
player.nodes[nodeNumber].selectedByAI = "True"
return sorted_indices, traced