xFS-bots 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xFS_bots/graph_models/__init__.py +0 -0
- xFS_bots/graph_models/_mg_sample.py +331 -0
- xFS_bots/graph_models/action_table.py +395 -0
- xFS_bots/graph_models/agent_database.py +77 -0
- xFS_bots/graph_models/analog_graph.py +130 -0
- xFS_bots/graph_models/analog_schemes.py +320 -0
- xFS_bots/graph_models/analog_schemes_aux.py +294 -0
- xFS_bots/graph_models/base_node.py +189 -0
- xFS_bots/graph_models/bfs.py +69 -0
- xFS_bots/graph_models/community.py +389 -0
- xFS_bots/graph_models/controverter.py +274 -0
- xFS_bots/graph_models/cyclical_navigator.py +241 -0
- xFS_bots/graph_models/dependency_seq.py +61 -0
- xFS_bots/graph_models/dfs.py +78 -0
- xFS_bots/graph_models/dir_imp_path.py +188 -0
- xFS_bots/graph_models/eb_graph_navigator.py +326 -0
- xFS_bots/graph_models/expr_tree.py +907 -0
- xFS_bots/graph_models/game_table.py +129 -0
- xFS_bots/graph_models/gcs.py +323 -0
- xFS_bots/graph_models/graph_gen.py +462 -0
- xFS_bots/graph_models/hg_obj_path.py +421 -0
- xFS_bots/graph_models/hg_obj_path_op.py +512 -0
- xFS_bots/graph_models/hypergraph.py +221 -0
- xFS_bots/graph_models/jamming_graph.py +399 -0
- xFS_bots/graph_models/lattice_graph_gen.py +402 -0
- xFS_bots/graph_models/micrograph.py +414 -0
- xFS_bots/graph_models/modular_graph.py +452 -0
- xFS_bots/graph_models/node_navigator_handler.py +31 -0
- xFS_bots/graph_models/node_path.py +345 -0
- xFS_bots/graph_models/node_priority_function.py +97 -0
- xFS_bots/graph_models/node_to_cycle.py +85 -0
- xFS_bots/graph_models/path_induction.py +260 -0
- xFS_bots/graph_models/pswap_graph.py +440 -0
- xFS_bots/graph_models/radial_subgraph.py +106 -0
- xFS_bots/graph_models/reactive_simple_graph_rules.py +210 -0
- xFS_bots/graph_models/shortest_paths.py +429 -0
- xFS_bots/graph_models/shortest_paths_approx.py +461 -0
- xFS_bots/graph_models/shortest_paths_type_st.py +119 -0
- xFS_bots/graph_models/spanning_tree.py +146 -0
- xFS_bots/graph_models/sparse_graph_gen.py +66 -0
- xFS_bots/graph_models/tree_gen.py +150 -0
- xFS_bots/graph_problems/__init__.py +0 -0
- xFS_bots/graph_problems/bkb.py +43 -0
- xFS_bots/graph_problems/bkb_ext.py +55 -0
- xFS_bots/graph_problems/cb.py +73 -0
- xFS_bots/graph_problems/cb_ext.py +61 -0
- xFS_bots/graph_problems/drb.py +67 -0
- xFS_bots/graph_problems/drb_ext.py +27 -0
- xFS_bots/graph_problems/easy_gen.py +429 -0
- xFS_bots/graph_problems/easy_gen_default_vars.py +104 -0
- xFS_bots/graph_problems/efb.py +145 -0
- xFS_bots/graph_problems/efb_ext.py +92 -0
- xFS_bots/graph_problems/hfb.py +106 -0
- xFS_bots/graph_problems/hfb_ext.py +31 -0
- xFS_bots/graph_problems/hte.py +319 -0
- xFS_bots/graph_problems/hte_ext.py +165 -0
- xFS_bots/graph_problems/ib.py +86 -0
- xFS_bots/graph_problems/ib_ext.py +65 -0
- xFS_bots/graph_problems/mkb.py +76 -0
- xFS_bots/graph_problems/mkb_ext.py +45 -0
- xFS_bots/graph_problems/mmb.py +126 -0
- xFS_bots/graph_problems/mmb_ext.py +34 -0
- xFS_bots/graph_problems/pdib.py +41 -0
- xFS_bots/graph_problems/pdib_ext.py +30 -0
- xFS_bots/graph_problems/pib.py +138 -0
- xFS_bots/graph_problems/pib_ext.py +35 -0
- xFS_bots/graph_problems/ptb.py +137 -0
- xFS_bots/graph_problems/ptb_ext.py +42 -0
- xFS_bots/graph_problems/rnb.py +228 -0
- xFS_bots/graph_problems/rnb_ext.py +90 -0
- xFS_bots/graph_problems/sb.py +79 -0
- xFS_bots/graph_problems/sb_ext.py +67 -0
- xFS_bots/graph_problems/sim_solution_search.py +92 -0
- xFS_bots/graph_problems/snb.py +115 -0
- xFS_bots/graph_problems/snb_ext.py +76 -0
- xFS_bots/graph_problems/tftmb.py +54 -0
- xFS_bots/graph_problems/tftmb_ext.py +56 -0
- xFS_bots/graph_problems/tsb.py +42 -0
- xFS_bots/graph_problems/tsb_ext.py +36 -0
- xFS_bots/graph_problems/vtb.py +13 -0
- xFS_bots/graph_problems/vtb_ext.py +44 -0
- xFS_bots/quant/__init__.py +0 -0
- xFS_bots/quant/agent_23.py +750 -0
- xFS_bots/quant/bool_rules.py +50 -0
- xFS_bots/quant/bull_graph.py +434 -0
- xFS_bots/quant/ce_agent.py +294 -0
- xFS_bots/quant/ce_net.py +228 -0
- xFS_bots/quant/cee_map.py +247 -0
- xFS_bots/quant/cnf_mask.py +182 -0
- xFS_bots/quant/cng.py +243 -0
- xFS_bots/quant/controverter_graph.py +247 -0
- xFS_bots/quant/default_graph_introproc.py +160 -0
- xFS_bots/quant/dual_obj.py +337 -0
- xFS_bots/quant/gl_expr_table.py +34 -0
- xFS_bots/quant/graph_introspector.py +125 -0
- xFS_bots/quant/gt_agent.py +94 -0
- xFS_bots/quant/hmm_agent.py +382 -0
- xFS_bots/quant/hscript_graph.py +501 -0
- xFS_bots/quant/hte_analog_induction.py +81 -0
- xFS_bots/quant/hte_aux.py +321 -0
- xFS_bots/quant/hte_navigator.py +226 -0
- xFS_bots/quant/levenschtein.py +89 -0
- xFS_bots/quant/middle_agent.py +221 -0
- xFS_bots/quant/middleman_graph.py +346 -0
- xFS_bots/quant/mob_graph.py +334 -0
- xFS_bots/quant/mutable_ce_net.py +46 -0
- xFS_bots/quant/mvec_agent.py +462 -0
- xFS_bots/quant/pd_graph.py +318 -0
- xFS_bots/quant/pd_inadvertency.py +266 -0
- xFS_bots/quant/poison_snt.py +277 -0
- xFS_bots/quant/pt_aux.py +346 -0
- xFS_bots/quant/qstruct.py +671 -0
- xFS_bots/quant/qstruct_aux.py +195 -0
- xFS_bots/quant/reactive_graph_introspector.py +103 -0
- xFS_bots/quant/rstruct.py +256 -0
- xFS_bots/quant/selection_rules.py +227 -0
- xFS_bots/quant/simple_hmm_env.py +141 -0
- xFS_bots/quant/square_nt.py +94 -0
- xFS_bots/quant/static_graph_introspector.py +129 -0
- xFS_bots/quant/strangle_form.py +567 -0
- xFS_bots/quant/strangle_graph.py +160 -0
- xFS_bots/quant/ul_vec_classifier.py +58 -0
- xFS_bots/quant/usg_controller.py +84 -0
- xFS_bots/quant/vt_graph.py +96 -0
- xfs_bots-0.0.1.dist-info/METADATA +208 -0
- xfs_bots-0.0.1.dist-info/RECORD +129 -0
- xfs_bots-0.0.1.dist-info/WHEEL +5 -0
- xfs_bots-0.0.1.dist-info/licenses/LICENSE.txt +19 -0
- xfs_bots-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
from morebs2.matrix_methods import *
|
|
2
|
+
from morebs2.search_space_iterator import *
|
|
3
|
+
from morebs2.numerical_generator import modulo_in_range,safe_modulo_in_range,prg_seqsort,prg_seqsort_ties
|
|
4
|
+
from morebs2.point_sorter import rank_sequence
|
|
5
|
+
from .tree_gen import SimpleCounter
|
|
6
|
+
from types import MethodType,FunctionType
|
|
7
|
+
from copy import deepcopy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
S := str, comma-separated integers, even non-zero number of integers;
|
|
12
|
+
(agent idn i_j,idn i_j move)*
|
|
13
|
+
|
|
14
|
+
return:
|
|
15
|
+
- dict, agent idn -> move idn.
|
|
16
|
+
"""
|
|
17
|
+
def string_to_agent_move_map(S):
|
|
18
|
+
q = string_to_vector(S)
|
|
19
|
+
assert len(q) > 0 and len(q) % 2 == 0
|
|
20
|
+
d = dict()
|
|
21
|
+
for i in range(0,len(q),2):
|
|
22
|
+
a,m = q[i],q[i+1]
|
|
23
|
+
d[a] = m
|
|
24
|
+
return d
|
|
25
|
+
|
|
26
|
+
def agent_move_map_to_string(amap):
|
|
27
|
+
assert type(amap) in {dict,defaultdict}
|
|
28
|
+
if len(amap) == 0: return ""
|
|
29
|
+
|
|
30
|
+
keys = sorted(amap.keys())
|
|
31
|
+
s = ""
|
|
32
|
+
for k in keys:
|
|
33
|
+
s += "{},{},".format(int(k),int(amap[k]))
|
|
34
|
+
return s[:-1]
|
|
35
|
+
|
|
36
|
+
def is_partial_agent_move_map_match(partial,whole):
|
|
37
|
+
for k,v in partial.items():
|
|
38
|
+
if whole[k] == v:
|
|
39
|
+
continue
|
|
40
|
+
return False
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
def agent_move_map__partial_key_match(S,amap):
|
|
44
|
+
key_matches = []
|
|
45
|
+
|
|
46
|
+
for k in S.keys():
|
|
47
|
+
whole = string_to_agent_move_map(k)
|
|
48
|
+
if is_partial_agent_move_map_match(amap,whole):
|
|
49
|
+
key_matches.append(k)
|
|
50
|
+
return sorted(key_matches)
|
|
51
|
+
|
|
52
|
+
def multi_agent_action_map__zeros(agents,agent2movesize_map,move_idn_counter):
|
|
53
|
+
# assign move identifiers to each agent's moves
|
|
54
|
+
agents = sorted(agents)
|
|
55
|
+
agent2move_map = {}
|
|
56
|
+
for a in agents:
|
|
57
|
+
l = agent2movesize_map[a]
|
|
58
|
+
agent2move_map[a] = [move_idn_counter() for _ in range(l)]
|
|
59
|
+
|
|
60
|
+
q = [agent2movesize_map[a] for a in agents]
|
|
61
|
+
bounds = np.array([np.zeros(len(agents),),q]).T
|
|
62
|
+
start_point = bounds[:,0]
|
|
63
|
+
column_order = [i for i in range(len(q))]
|
|
64
|
+
ssi_hop = np.array(q)
|
|
65
|
+
ssi = SearchSpaceIterator(bounds,start_point,column_order,\
|
|
66
|
+
ssi_hop,cycleOn = False,cycleIs = 0)
|
|
67
|
+
|
|
68
|
+
T = {}
|
|
69
|
+
v = {a:0 for a in agents}
|
|
70
|
+
while not ssi.finished():
|
|
71
|
+
# get the index
|
|
72
|
+
n = next(ssi)
|
|
73
|
+
# get the dict
|
|
74
|
+
d = {agents[i]:agent2move_map[i][int(n_)] for (i,n_) in enumerate(n)}
|
|
75
|
+
|
|
76
|
+
# convert dict to string
|
|
77
|
+
s = agent_move_map_to_string(d)
|
|
78
|
+
|
|
79
|
+
# load element
|
|
80
|
+
T[s] = deepcopy(v)
|
|
81
|
+
|
|
82
|
+
return T,agent2move_map
|
|
83
|
+
|
|
84
|
+
def bracket_assignment_agent_action_payoff(T,agent_idn,agent_moveset,agent_action_value_range,\
|
|
85
|
+
bracket_size_range,prg):
|
|
86
|
+
|
|
87
|
+
actions = sorted(agent_moveset)
|
|
88
|
+
num_brackets = modulo_in_range(int(prg()),bracket_size_range)
|
|
89
|
+
##print(agent_idn," num brackets: ",num_brackets)
|
|
90
|
+
v = n_partition_for_range(agent_action_value_range,num_brackets)
|
|
91
|
+
|
|
92
|
+
actions = prg_seqsort(actions,prg)
|
|
93
|
+
action_brackets = []
|
|
94
|
+
for i,a2 in enumerate(actions):
|
|
95
|
+
i2 = i % num_brackets
|
|
96
|
+
r2 = v[i2:i2+2]
|
|
97
|
+
action_brackets.append(r2)
|
|
98
|
+
|
|
99
|
+
for (i,a) in enumerate(actions):
|
|
100
|
+
amap = {agent_idn:a}
|
|
101
|
+
keys = agent_move_map__partial_key_match(T,amap)
|
|
102
|
+
r2 = action_brackets[i]
|
|
103
|
+
for k in keys:
|
|
104
|
+
value = round(modulo_in_range(prg(),r2),5)
|
|
105
|
+
T[k][agent_idn] = value
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
table that can be used for (immediate XOR cumulative XOR duration of) payoffs from
|
|
110
|
+
actions by agents.
|
|
111
|
+
|
|
112
|
+
Typically used as container for immediate payoffs.
|
|
113
|
+
"""
|
|
114
|
+
class MultiAgentActionTable:
|
|
115
|
+
|
|
116
|
+
"""
|
|
117
|
+
agents := set, agent idns
|
|
118
|
+
agent_action_map := dict,
|
|
119
|
+
stringized repr. of (agent idn,move idn) -> agent idn -> value from move.
|
|
120
|
+
"""
|
|
121
|
+
def __init__(self,agents,agent_action_map):
|
|
122
|
+
self.agents = agents
|
|
123
|
+
self.agent_action_map = agent_action_map
|
|
124
|
+
self.agent2move_map = None
|
|
125
|
+
self.check_arguments()
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
def __str__(self):
|
|
129
|
+
keys = sorted(self.agent_action_map.keys())
|
|
130
|
+
S = ""
|
|
131
|
+
for k in keys:
|
|
132
|
+
S += self.stringize_action_profile(k) + "\n" + "-" * 50 + "\n"
|
|
133
|
+
return S
|
|
134
|
+
|
|
135
|
+
def __getitem__(self, key):
|
|
136
|
+
if key in self.agent_action_map:
|
|
137
|
+
return self.agent_action_map[key]
|
|
138
|
+
assert False
|
|
139
|
+
|
|
140
|
+
def stringize_action_profile(self,k):
|
|
141
|
+
m2 = string_to_agent_move_map(k)
|
|
142
|
+
x = self.agent_action_map[k]
|
|
143
|
+
keys = sorted(m2.keys())
|
|
144
|
+
|
|
145
|
+
s = ""
|
|
146
|
+
for k2 in keys:
|
|
147
|
+
s += "agent {} move {} value {}\n".format(k2,m2[k2],x[k2])
|
|
148
|
+
return s
|
|
149
|
+
|
|
150
|
+
################### preprocessing moves for info on `agent_action_map`
|
|
151
|
+
def check_arguments(self):
|
|
152
|
+
assert type(self.agents) == set
|
|
153
|
+
self.agent2move_map = self.agent_to_move_map()
|
|
154
|
+
assert len(self.agent_action_map) == self.total_number_of_move_combinations()
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
def agent_to_move_map(self):
|
|
158
|
+
d = defaultdict(set)
|
|
159
|
+
for k,v in self.agent_action_map.items():
|
|
160
|
+
q = string_to_agent_move_map(k)
|
|
161
|
+
for k2,v2 in q.items():
|
|
162
|
+
d[k2] |= {v2}
|
|
163
|
+
assert type(v) in {dict,defaultdict}
|
|
164
|
+
assert set(v.keys()) == self.agents
|
|
165
|
+
return d
|
|
166
|
+
|
|
167
|
+
def total_number_of_move_combinations(self):
|
|
168
|
+
l = 1
|
|
169
|
+
for v in self.agent2move_map.values():
|
|
170
|
+
l = l * len(v)
|
|
171
|
+
return l
|
|
172
|
+
|
|
173
|
+
############################## used to determine lattice points of n-dimensional
|
|
174
|
+
############################## game table prism.
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
sort_index := 0 -> min,
|
|
178
|
+
1 -> max,
|
|
179
|
+
2 -> mean.
|
|
180
|
+
"""
|
|
181
|
+
def sort_agent_moves(self,a_idn,sort_index,other_agent_moves={}):
|
|
182
|
+
assert sort_index in {0,1,2}
|
|
183
|
+
|
|
184
|
+
move_info = []
|
|
185
|
+
for m in self.agent2move_map[a_idn]:
|
|
186
|
+
info = self.base_info_on_agent_move(a_idn,m,other_agent_moves)
|
|
187
|
+
move_info.append((int(m),info))
|
|
188
|
+
q = sorted(move_info,key=lambda x:x[1][sort_index])
|
|
189
|
+
return [(q_[0],q_[1][sort_index]) for q_ in q]
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
Determines the rank of agent `a_idn` conducting move `move_idn`
|
|
193
|
+
w.r.t. the others. For every element E in `agent_action_map` that
|
|
194
|
+
has agent `a_idn` conduct `move_idn`, ranks value of agent with the
|
|
195
|
+
costs of the other agents, producing rank r.
|
|
196
|
+
|
|
197
|
+
NOTE: ordering of rank is least=0, greatest=max.
|
|
198
|
+
|
|
199
|
+
return:
|
|
200
|
+
- list, ranks of value for agent conducting move w.r.t. other agents.
|
|
201
|
+
"""
|
|
202
|
+
def possible_ranks_of_agent_by_move(self,a_idn,move_idn,other_agent_moves={}):
|
|
203
|
+
self.query_parameter_assertion(a_idn,move_idn,other_agent_moves)
|
|
204
|
+
|
|
205
|
+
amap = {a_idn:move_idn}
|
|
206
|
+
amap.update(other_agent_moves)
|
|
207
|
+
|
|
208
|
+
keys = agent_move_map__partial_key_match(self.agent_action_map,amap)
|
|
209
|
+
ranks = []
|
|
210
|
+
for k in keys:
|
|
211
|
+
v = self.agent_action_map[k]
|
|
212
|
+
v_ = [(k2,v2) for k2,v2 in v.items()]
|
|
213
|
+
q = rank_sequence(v_,vf=lambda x:x[1],\
|
|
214
|
+
element_output_function=lambda x:x[0],output_type=dict)
|
|
215
|
+
r = q[a_idn]
|
|
216
|
+
ranks.append(r)
|
|
217
|
+
return ranks
|
|
218
|
+
|
|
219
|
+
"""
|
|
220
|
+
return:
|
|
221
|
+
- (min,max,mean) of agent move payoffs
|
|
222
|
+
"""
|
|
223
|
+
def base_info_on_agent_move(self,a_idn,move_idn,other_agent_moves={}):
|
|
224
|
+
self.query_parameter_assertion(a_idn,move_idn,other_agent_moves)
|
|
225
|
+
|
|
226
|
+
amap = {a_idn:move_idn}
|
|
227
|
+
amap.update(other_agent_moves)
|
|
228
|
+
keys = agent_move_map__partial_key_match(self.agent_action_map,amap)
|
|
229
|
+
assert len(keys) > 0
|
|
230
|
+
|
|
231
|
+
vs = []
|
|
232
|
+
for k in keys:
|
|
233
|
+
v = self.agent_action_map[k][a_idn]
|
|
234
|
+
vs.append(v)
|
|
235
|
+
|
|
236
|
+
return np.min(vs),np.max(vs),np.round(np.mean(vs),5)
|
|
237
|
+
|
|
238
|
+
"""
|
|
239
|
+
calculates the move by agent `a_idn` that would yield the minumum mean paypoff by agents in
|
|
240
|
+
set `other_idns`. If `other_agent_moves` is not empty, only those moves by the other agents
|
|
241
|
+
are considered in the ranking calculation.
|
|
242
|
+
"""
|
|
243
|
+
def agent_move_for_minmean_value_by_other_agents(self,a_idn,other_idns,other_agent_moves={},\
|
|
244
|
+
prg = None):
|
|
245
|
+
return self.agent_countermove_for_other_agents(a_idn,other_idns,other_agent_moves,\
|
|
246
|
+
2,2,prg)
|
|
247
|
+
|
|
248
|
+
"""
|
|
249
|
+
Calculates the move by agent that would yield the "minimal" payoff,
|
|
250
|
+
MIN (MIN|MAX|MEAN (MIN|MAX|MEAN(others))),
|
|
251
|
+
by the other agents. See description for
|
|
252
|
+
function<MultiAgentActionTable.agent_move_for_info_on_other_agents> for how this "minimal"
|
|
253
|
+
payoff is calculated.
|
|
254
|
+
"""
|
|
255
|
+
def agent_countermove_for_other_agents(self,a_idn,other_idns,other_agent_moves,\
|
|
256
|
+
index0,index1,prg = None):
|
|
257
|
+
|
|
258
|
+
other_info = self.agent_move_for_info_on_other_agents(a_idn,other_idns,other_agent_moves,\
|
|
259
|
+
index0,index1)
|
|
260
|
+
other_info = [(k,v) for k,v in other_info.items()]
|
|
261
|
+
|
|
262
|
+
if type(prg) != type(None):
|
|
263
|
+
return int(prg_seqsort_ties(other_info,prg,vf=lambda x:x[1])[0][0])
|
|
264
|
+
return int(sorted(other_info,key=lambda x:x[1])[0][0])
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
index0 := (0|1|2) <-> (min|max|mean), payoff for other agents
|
|
268
|
+
index1 := (0|1|2) <-> (min|max|mean), summarization (1 value) of other agents' payoff map.
|
|
269
|
+
|
|
270
|
+
return:
|
|
271
|
+
- agent move idn -> payoff info specified by the criteria (index0,index1).
|
|
272
|
+
"""
|
|
273
|
+
def agent_move_for_info_on_other_agents(self,a_idn,other_idns,other_agent_moves={},index0=2,\
|
|
274
|
+
index1=2):
|
|
275
|
+
assert index0 in {0,1,2}
|
|
276
|
+
assert index1 in {0,1,2}
|
|
277
|
+
|
|
278
|
+
def fx(S):
|
|
279
|
+
if index1 == 0:
|
|
280
|
+
return np.min(S)
|
|
281
|
+
elif index1 == 1:
|
|
282
|
+
return np.max(S)
|
|
283
|
+
else:
|
|
284
|
+
return np.round(np.mean(S),5)
|
|
285
|
+
|
|
286
|
+
move_info = {}
|
|
287
|
+
for m in self.agent2move_map[a_idn]:
|
|
288
|
+
dx = self.base_info_on_other_agents(a_idn,m,other_idns,other_agent_moves)
|
|
289
|
+
s = [v[index0] for v in dx.values()]
|
|
290
|
+
s = fx(s)
|
|
291
|
+
move_info[m] = s
|
|
292
|
+
return move_info
|
|
293
|
+
|
|
294
|
+
"""
|
|
295
|
+
given agent `a_idn` that conducts move `move_idn`, a map
|
|
296
|
+
|
|
297
|
+
other agent idn -> (min,max,mean) payoff values
|
|
298
|
+
|
|
299
|
+
is produced.
|
|
300
|
+
"""
|
|
301
|
+
def base_info_on_other_agents(self,a_idn,move_idn,other_idns,other_agent_moves={}):
|
|
302
|
+
self.query_parameter_assertion(a_idn,move_idn,other_agent_moves)
|
|
303
|
+
assert other_idns.issubset(self.agents) and a_idn not in other_idns
|
|
304
|
+
|
|
305
|
+
amap = {a_idn:move_idn}
|
|
306
|
+
amap.update(other_agent_moves)
|
|
307
|
+
keys = agent_move_map__partial_key_match(self.agent_action_map,amap)
|
|
308
|
+
assert len(keys) > 0
|
|
309
|
+
|
|
310
|
+
vs = []
|
|
311
|
+
other_agent_mean = defaultdict(float)
|
|
312
|
+
other_agent_min = {o:float('inf') for o in other_idns}
|
|
313
|
+
other_agent_max = {o:-float('inf') for o in other_idns}
|
|
314
|
+
|
|
315
|
+
for k in keys:
|
|
316
|
+
v = self.agent_action_map[k]
|
|
317
|
+
for o in other_idns:
|
|
318
|
+
v2 = v[o]
|
|
319
|
+
other_agent_mean[o] += v2
|
|
320
|
+
other_agent_min[o] = min([v2,other_agent_min[o]])
|
|
321
|
+
other_agent_max[o] = max([v2,other_agent_max[o]])
|
|
322
|
+
for o in other_idns:
|
|
323
|
+
other_agent_mean[o] = round(other_agent_mean[o] / len(keys),5)
|
|
324
|
+
|
|
325
|
+
other_agent_info = {o:\
|
|
326
|
+
(other_agent_min[o],other_agent_max[o],other_agent_mean[o]) \
|
|
327
|
+
for o in other_idns}
|
|
328
|
+
return other_agent_info
|
|
329
|
+
|
|
330
|
+
def query_parameter_assertion(self,a_idn,move_idn,other_agent_moves):
|
|
331
|
+
assert a_idn in self.agents
|
|
332
|
+
assert move_idn in self.agent2move_map[a_idn]
|
|
333
|
+
assert type(other_agent_moves) == dict
|
|
334
|
+
assert set(other_agent_moves.keys()).issubset(self.agents)
|
|
335
|
+
|
|
336
|
+
@staticmethod
|
|
337
|
+
def generate_instance__type_prng(agents,agent2movesize_map,agent_action_value_range,\
|
|
338
|
+
prg,move_idn_counter=SimpleCounter(0).__next__):
|
|
339
|
+
agent_action_value_range = MultiAgentActionTable.generate_instance__parameter_assertion(\
|
|
340
|
+
agents,agent2movesize_map,agent_action_value_range,prg)
|
|
341
|
+
|
|
342
|
+
T,_ = multi_agent_action_map__zeros(agents,agent2movesize_map,move_idn_counter)
|
|
343
|
+
agents_ = sorted(agents)
|
|
344
|
+
|
|
345
|
+
keys = sorted(T.keys())
|
|
346
|
+
for k in keys:
|
|
347
|
+
v = T[k]
|
|
348
|
+
for k2 in agents_:
|
|
349
|
+
v[k2] = round(safe_modulo_in_range(prg(),\
|
|
350
|
+
agent_action_value_range[k2]),5)
|
|
351
|
+
return MultiAgentActionTable(agents,T)
|
|
352
|
+
|
|
353
|
+
@staticmethod
|
|
354
|
+
def generate_instance__type_strict_percentile(agents,agent2movesize_map,agent_action_value_range,\
|
|
355
|
+
prg,bracket_size_range,move_idn_counter=SimpleCounter(0).__next__):
|
|
356
|
+
|
|
357
|
+
agent_action_value_range = MultiAgentActionTable.generate_instance__parameter_assertion(\
|
|
358
|
+
agents,agent2movesize_map,agent_action_value_range,prg)
|
|
359
|
+
|
|
360
|
+
T,M = multi_agent_action_map__zeros(agents,agent2movesize_map,move_idn_counter)
|
|
361
|
+
agents = sorted(agents)
|
|
362
|
+
for agent_idn in agents:
|
|
363
|
+
agent_moveset = M[agent_idn]
|
|
364
|
+
aarange = agent_action_value_range[agent_idn]
|
|
365
|
+
bracket_assignment_agent_action_payoff(T,agent_idn,agent_moveset,\
|
|
366
|
+
aarange,bracket_size_range,prg)
|
|
367
|
+
return MultiAgentActionTable(set(agents),T)
|
|
368
|
+
|
|
369
|
+
@staticmethod
|
|
370
|
+
def generate_instance__parameter_assertion(agents,agent2movesize_map,agent_action_value_range,\
|
|
371
|
+
prg):
|
|
372
|
+
assert type(prg) in {FunctionType,MethodType}
|
|
373
|
+
|
|
374
|
+
agent_action_value_range = MultiAgentActionTable.format_agent_action_value_range(\
|
|
375
|
+
agents,agent_action_value_range)
|
|
376
|
+
|
|
377
|
+
assert set(agent2movesize_map.keys()) == agents
|
|
378
|
+
for v in agent2movesize_map.values(): assert v > 0
|
|
379
|
+
return agent_action_value_range
|
|
380
|
+
|
|
381
|
+
@staticmethod
|
|
382
|
+
def format_agent_action_value_range(agents,agent_action_value_range):
|
|
383
|
+
|
|
384
|
+
if type(agent_action_value_range) == dict:
|
|
385
|
+
assert set(agent_action_value_range.keys()) == agents
|
|
386
|
+
for v in agent_action_value_range.values():
|
|
387
|
+
assert v[0] <= v[1]
|
|
388
|
+
else:
|
|
389
|
+
assert agent_action_value_range[0] <= agent_action_value_range[1]
|
|
390
|
+
agents = sorted(agents)
|
|
391
|
+
d = {}
|
|
392
|
+
for k in agents:
|
|
393
|
+
d[k] = deepcopy(agent_action_value_range)
|
|
394
|
+
agent_action_value_range = d
|
|
395
|
+
return agent_action_value_range
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
|
|
4
|
+
class AgentInfo:
|
|
5
|
+
|
|
6
|
+
def __init__(self,info_type):
|
|
7
|
+
assert info_type in {str,int,float,\
|
|
8
|
+
list,set,np.ndarray}
|
|
9
|
+
self.info_type = info_type
|
|
10
|
+
self.info = None
|
|
11
|
+
self.last_info = None
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return str(self.info)
|
|
16
|
+
|
|
17
|
+
def __add__(self,s):
|
|
18
|
+
assert type(s) == self.info_type, "got {}".format(type(s))
|
|
19
|
+
q = deepcopy(self)
|
|
20
|
+
q.last_info = s
|
|
21
|
+
if type(q.info) == type(None):
|
|
22
|
+
if q.info_type == np.ndarray:
|
|
23
|
+
q.info = np.array([s])
|
|
24
|
+
else:
|
|
25
|
+
q.info = s
|
|
26
|
+
elif q.info_type in {str,int,float}:
|
|
27
|
+
q.info += s
|
|
28
|
+
elif q.info_type == list:
|
|
29
|
+
q.info.append(s)
|
|
30
|
+
elif q.info_type == set:
|
|
31
|
+
q.info |= s
|
|
32
|
+
else:
|
|
33
|
+
q.info = np.vstack((q.info,s))
|
|
34
|
+
return q
|
|
35
|
+
|
|
36
|
+
class SimpleAgentDB:
|
|
37
|
+
|
|
38
|
+
def __init__(self,info_type):
|
|
39
|
+
self.info_type = info_type
|
|
40
|
+
self.agent_idns = []
|
|
41
|
+
self.agent_info = dict()
|
|
42
|
+
self.c = 0
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
S = ""
|
|
46
|
+
for k,v in self.agent_info.items():
|
|
47
|
+
S += str(k) + "\n" + str(v) + "\n\n"
|
|
48
|
+
return S
|
|
49
|
+
|
|
50
|
+
def add_agent(self):
|
|
51
|
+
self.add_agent_(self.c)
|
|
52
|
+
self.c += 1
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
def add_agent_(self,idn):
|
|
56
|
+
assert idn not in self.agent_idns
|
|
57
|
+
self.agent_idns.append(idn)
|
|
58
|
+
self.agent_info[idn] = AgentInfo(self.info_type)
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
def update_info(self,idn,info):
|
|
62
|
+
if idn not in self.agent_idns:
|
|
63
|
+
self.add_agent_(idn)
|
|
64
|
+
self.agent_info[idn] = self.agent_info[idn] + info
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
def last_info_for_agent(self,idn):
|
|
68
|
+
if idn not in self.agent_idns: return None
|
|
69
|
+
return self.agent_info[idn].last_info
|
|
70
|
+
|
|
71
|
+
def delete_agent_info(self,idn):
|
|
72
|
+
if idn not in self.agent_idns: return
|
|
73
|
+
|
|
74
|
+
i = self.agent_idns.index(idn)
|
|
75
|
+
self.agent_idns.pop(i)
|
|
76
|
+
del self.agent_info[idn]
|
|
77
|
+
return
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from .analog_schemes_aux import *
|
|
2
|
+
from .radial_subgraph import *
|
|
3
|
+
|
|
4
|
+
DEFAULT_ANALOG_GRAPH_SUBGRAPH_RADIUS_RANGE = [1,3]
|
|
5
|
+
|
|
6
|
+
# NOTE: duplicate code?
|
|
7
|
+
def dict_diff(ref_dict, other_dict):
|
|
8
|
+
c = 0
|
|
9
|
+
for k,v in ref_dict.items():
|
|
10
|
+
if k not in other_dict:
|
|
11
|
+
c += 1
|
|
12
|
+
continue
|
|
13
|
+
v2 = other_dict[k]
|
|
14
|
+
if v != v2:
|
|
15
|
+
c += 1
|
|
16
|
+
return c
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# TODO: test this.
|
|
20
|
+
"""
|
|
21
|
+
reference_graph := defaultdict, graph
|
|
22
|
+
isomap := node of reference graph -> node of another graph
|
|
23
|
+
prg := PRNG
|
|
24
|
+
isomorphic_subgraph_radius_range := range
|
|
25
|
+
"""
|
|
26
|
+
class AnalogGraph:
|
|
27
|
+
|
|
28
|
+
def __init__(self,reference_graph,isomap,prg,isomorphic_subgraph_radius_range=DEFAULT_ANALOG_GRAPH_SUBGRAPH_RADIUS_RANGE):
|
|
29
|
+
assert type(reference_graph) == defaultdict
|
|
30
|
+
assert type(isomap) == dict
|
|
31
|
+
assert type(prg) in {MethodType,FunctionType}
|
|
32
|
+
assert is_valid_range(isomorphic_subgraph_radius_range,True,False)
|
|
33
|
+
|
|
34
|
+
self.reference_graph = reference_graph
|
|
35
|
+
self.isomap = isomap
|
|
36
|
+
self.prg = prg
|
|
37
|
+
self.iso_sg_radius_range = isomorphic_subgraph_radius_range
|
|
38
|
+
self.preproc()
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
def preproc(self):
|
|
42
|
+
self.qsf = QuickSubgraphFetcher(self.reference_graph,self.prg)
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
def draw_analogy_to(self,G,exact_node_mapping_ratio:float):
|
|
46
|
+
assert type(G) == defaultdict
|
|
47
|
+
assert 0.0 <= exact_node_mapping_ratio <= 1.0
|
|
48
|
+
#assert AnalogGraph.graph_is_analogical(self.reference_graph,G,self.isomap)
|
|
49
|
+
candidates = sorted(self.isomap.keys())
|
|
50
|
+
|
|
51
|
+
def prg_(): return int(self.prg())
|
|
52
|
+
|
|
53
|
+
num_exact_mapping = ceil(len(candidates) * exact_node_mapping_ratio)
|
|
54
|
+
exact_nodes = prg_choose_n(candidates,num_exact_mapping,prg_,is_unique_picker=True)
|
|
55
|
+
|
|
56
|
+
node_analogy = {}
|
|
57
|
+
got = set()
|
|
58
|
+
def analogical_node(n):
|
|
59
|
+
if n in exact_nodes:
|
|
60
|
+
return self.isomap[n]
|
|
61
|
+
|
|
62
|
+
# fetch the subgraph
|
|
63
|
+
ref_sg = self.subgraph_for_node(n)
|
|
64
|
+
# calculate the isomorphisms
|
|
65
|
+
mg = MicroGraph(ref_sg)
|
|
66
|
+
mg2 = MicroGraph(G)
|
|
67
|
+
|
|
68
|
+
Q = mg2.subgraph_isomorphism(mg,all_iso=True,size_limit=200,search_candidate_limit=50000)#prg=self.prg)
|
|
69
|
+
if len(Q) == 0: return None
|
|
70
|
+
|
|
71
|
+
# approach #1
|
|
72
|
+
"""
|
|
73
|
+
# choose an isomorphism
|
|
74
|
+
index = int(self.prg()) % len(Q)
|
|
75
|
+
isomorphism = Q[index]
|
|
76
|
+
print("ISO ",Q[index])
|
|
77
|
+
|
|
78
|
+
isomorphism = {v:k for k,v in isomorphism}
|
|
79
|
+
|
|
80
|
+
if n not in isomorphism: return None
|
|
81
|
+
return isomorphism[n]
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
# approach #2
|
|
85
|
+
qs = []
|
|
86
|
+
for iso in Q:
|
|
87
|
+
iso2 = {v:k for k,v in iso}
|
|
88
|
+
if n not in iso2:
|
|
89
|
+
continue
|
|
90
|
+
qs.append(iso2[n])
|
|
91
|
+
|
|
92
|
+
untaken = set(qs) - got
|
|
93
|
+
if len(untaken) == 0: return None
|
|
94
|
+
|
|
95
|
+
untaken = sorted(untaken)
|
|
96
|
+
index = int(self.prg()) % len(untaken)
|
|
97
|
+
return untaken[index]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
for k in self.isomap.keys():
|
|
101
|
+
x = analogical_node(k)
|
|
102
|
+
##print("analogical node for {}:{}".format(k,x))
|
|
103
|
+
if type(x) != type(None):
|
|
104
|
+
node_analogy[k] = x
|
|
105
|
+
got |= {x}
|
|
106
|
+
|
|
107
|
+
return node_analogy
|
|
108
|
+
|
|
109
|
+
def subgraph_for_node(self,n):
|
|
110
|
+
radius = modulo_in_range(int(self.prg()),self.iso_sg_radius_range)
|
|
111
|
+
return self.qsf.subgraph(n,radius)
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def graph_is_analogical(ref_graph,analogy_graph,isomap):
|
|
115
|
+
for k,v in isomap.items():
|
|
116
|
+
if k not in ref_graph: return False
|
|
117
|
+
if v not in analogy_graph: return False
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
class AnalogGraphGroup:
|
|
121
|
+
|
|
122
|
+
def __init__(self,analog_graphs,isomaps):
|
|
123
|
+
assert len(analog_graphs) > 1
|
|
124
|
+
assert len(analog_graphs) == len(isomaps) + 1
|
|
125
|
+
|
|
126
|
+
for x in analog_graphs: assert type(x) == AnalogGraph
|
|
127
|
+
for x in isomaps: assert type(x) == dict
|
|
128
|
+
self.analog_graphs = analog_graphs
|
|
129
|
+
self.isomaps = isomaps
|
|
130
|
+
return
|