def enforce_binary(x_searchers, t_max): """Enforce variable to be binary""" old_x_searchers = x_searchers m = ext.get_m_from_tuple(x_searchers) S = ext.get_set_searchers(m)[0] x_keys = old_x_searchers.keys() # loop searchers for s in S: # loop through time for t in range(t_max + 1): v_t = [k[1] for k in x_keys if s == k[0] and t == k[2]] var_value = [old_x_searchers.get((s, v, t)) for v in v_t] # find max value idx at time t mx = var_value.index(max(var_value)) # everything else is zero for v in v_t: if v == v_t[mx]: x_searchers[(s, v, t)] = 1 else: x_searchers[(s, v, t)] = 0 # for debugging only! if old_x_searchers != x_searchers: print('-X-X-X-X-X-X- Eureka! -X-X-X-X-X-X-') return x_searchers
def plot_searchers_position(g, folder_name, my_layout, x_searchers: dict, t: int): """plot results of searchers position""" m = ext.get_m_from_tuple(x_searchers) V, n = ext.get_set_vertices(g) S = ext.get_set_searchers(m)[0] g.vs["color"] = "white" for s in S: for v in V: my_value = x_searchers.get((s, v, t)) if my_value == 1: v_idx = ext.get_python_idx(v) g.vs[v_idx]["color"] = "blue" name_file = folder_name + "/" + g["name"] + "_t" + str(t) + ".png" plot(g, name_file, layout=my_layout, figsize=(3, 3), bbox=(400, 400), margin=15, dpi=400) return name_file
def plot_searchers_and_target(g, folder_path, my_layout, target, searchers, t): """plot results of searchers position and true position of the target""" m = len(list(searchers.keys())) S = ext.get_set_searchers(list(range(m)))[0] g.vs["color"] = "white" for s_id in S: s = searchers[s_id] my_searcher_vertex = s.path_taken[t] v_idx = ext.get_python_idx(my_searcher_vertex) g.vs[v_idx]["color"] = "blue" # plot target v_target = target.stored_v_true[t] v_t_idx = ext.get_python_idx(v_target) if target.capture_time == t: g.vs[v_t_idx]["color"] = "green" else: g.vs[v_t_idx]["color"] = "red" name_file = folder_path + "/" + g["name"] + "_t" + str(t) + ".png" plot(g, name_file, layout=my_layout, figsize=(3, 3), bbox=(400, 400), margin=15, dpi=400) plt.close() return name_file
def get_vertices_and_steps(G, deadline, searchers): """Extract information from the user provided graph and information on searchers For each time step, find which vertices each searcher is allowed to be""" start = ext.get_searchers_positions(searchers) # S_ and Tau S, m = ext.get_set_searchers(start) Tau = ext.get_set_time(deadline) # get vertices V, n = ext.get_set_vertices(G) # shortest path lengths spl = ext.get_length_short_paths(G) # find V^tau(t) = {v in V} --> possible v(t) in optimal solution vertices_t = {} # find V^tau(v) = {t in Tau} --> possible t(v) in optimal solution times_v = {} start_idx = ext.get_python_idx(start) for s in S: s_idx = ext.get_python_idx(s) # initial position vertices_t[s, 0] = [start[s_idx]] # starting at t = 1 (idx = 1), it begins to move for t in Tau: vertices_t[s, t] = [] # find the nodes that are within t of distance (thus can be reached at t) for v in V: v_idx = ext.get_python_idx(v) dummy_var = spl[start_idx[s_idx]][v_idx] if dummy_var <= t: vertices_t[s, t].append(v) # find times allowed for each vertex for v in V: times_v[s, v] = [] if v == start[s_idx]: times_v[s, v] = [0] for t in Tau: if v in vertices_t[s, t]: times_v[s, v].append(t) # find dummy goal vertex and T + 1 v_g = ext.get_label_dummy_goal(V) t_g = ext.get_last_t(Tau) # append dummy goal vertices_t[s, t_g] = [v_g] # at T + 1, searcher is at dummy goal vertex times_v[s, v_g] = [ t_g ] # the only time allowed for the dummy goal vertex is T + 1 return start, vertices_t, times_v
def next_from_path(path: dict, t_plan: int): """ get new position of searchers as new_pos = {s: v}""" m = ext.get_m_from_tuple(path) S = ext.get_set_searchers(m)[0] new_pos = dict() for s_id in S: new_pos[s_id] = path[(s_id, t_plan)] return new_pos
def test_get_set_and_idx_searchers(): list_input = [5, 2] S, m = ext.get_set_searchers(list_input) S_, m_ = ext.get_idx_searchers(list_input) assert S == [1, 2] assert S_ == [0, 1] assert m == 2 assert m_ == 2 dict_input = {1: 10, 2: 9, 3: 8} S, m = ext.get_set_searchers(dict_input) S_, m_ = ext.get_idx_searchers(dict_input) assert S == [1, 2, 3] assert S_ == [0, 1, 2] assert m == 3 assert m_ == 3 dict_input2 = dict() # x_s(s, v, t) dict_input2[(1, 1, 0)] = 1 dict_input2[(1, 2, 1)] = 1 dict_input2[(1, 3, 2)] = 1 dict_input2[(2, 4, 0)] = 1 dict_input2[(2, 5, 1)] = 1 dict_input2[(2, 6, 2)] = 1 S, m = ext.get_set_searchers(dict_input2) S_, m_ = ext.get_idx_searchers(dict_input2) assert S == [1, 2] assert S_ == [0, 1] assert m == 2 assert m_ == 2 int_input = 5 S, m = ext.get_set_searchers(int_input) S_, m_ = ext.get_idx_searchers(int_input) assert S == [1, 2, 3, 4, 5] assert S_ == [0, 1, 2, 3, 4] assert m == 5 assert m_ == 5
def add_searcher_variables(md, g, start: list, vertices_t: dict, deadline: int): """Add variables related to the searchers on the model: X : searchers location at each time step Y : searchers movement from t to t + 1""" [X, Y] = ext.init_dict_variables(2) S, m = ext.get_set_searchers(start) var_for_test = {} list_x_name = [] list_y_name = [] # T_ext = {0, 1,..., tau} T_ext = ext.get_set_time_u_0(deadline) # searcher s is located at vertex v at time t for s in S: for t in T_ext: # get vertices that searcher s can be at time t (last t needs to be dummy goal vertex) # v_t returns the label of the vertices v_t = vertices_t.get((s, t)) for v in v_t: # variable for: searcher position -- for each node the searcher can be at each time dummy_x_name = "x[%d,%d,%d]" % (s, v, t) if dummy_x_name not in list_x_name: # if didn't add already, do it X[s, v, t] = md.addVar(vtype="BINARY", name=dummy_x_name) list_x_name.append(dummy_x_name) # find Y[s, u, v, t] : from u, searcher s can move to u at t + 1 # returns vertices labels my_next_v = cm.get_next_vertices(g, s, v, t, vertices_t, T_ext) if my_next_v is not None: for u in my_next_v: dummy_y_name = "y[%d,%d,%d,%d]" % (s, v, u, t) if dummy_y_name not in list_y_name: Y[s, v, u, t] = md.addVar(vtype="BINARY", name=dummy_y_name) list_y_name.append(dummy_y_name) var_for_test.update({'x': list_x_name}) var_for_test.update({'y': list_y_name}) my_vars = {'x': X, 'y': Y} return my_vars, var_for_test
def init_temp_path(searchers: dict, horizon: int): """If no path was computed yet, assume all searchers will stay at the start position :param searchers: dictionary of searcher class :param horizon: planning horizon (h)""" Tau = ext.get_set_time_u_0(horizon) start = ext.get_searchers_positions(searchers) # S_ and Tau S, m = ext.get_set_searchers(start) temp_pi = dict() temp_pi['current_searcher'] = None for s in S: s_idx = ext.get_python_idx(s) v = start[s_idx] for t in Tau: temp_pi[s, t] = v return temp_pi
def add_searcher_constraints(md, g, my_vars: dict, start: list, vertices_t: dict, deadline: int): """Define constraints pertinent to the searchers path """ # get variables X = get_var(my_vars, 'x') Y = get_var(my_vars, 'y') S, m = ext.get_set_searchers(start) Tau_ext = ext.get_set_time_u_0(deadline) # legality of the paths, for all s = {1,...m} for s in S: # 0, 1, 2... T for t in Tau_ext: v_t = vertices_t.get((s, t)) # each searcher can only be at one place at each time (including the start vertex), Eq. (1, 7) if t == 0: md.addConstr(X[s, v_t[0], 0] == 1) for u in v_t: my_next_v = cm.get_next_vertices(g, s, u, t, vertices_t, Tau_ext) my_previous_v = cm.get_previous_vertices( g, s, u, t, vertices_t) if my_next_v is not None: # (Eq. 9) searcher can only move to: i in delta_prime(v) AND V^tau(t+1) # sum == 1 if searcher is at u, sum == zero if searcher is not at u (depends on X[s, u, t]) md.addConstr( quicksum(Y[s, u, i, t] for i in my_next_v) == X[s, u, t]) if my_previous_v is not None: # (Eq. 8) searcher can only move to v from j in delta_prime(v) AND V^tau(t-1) md.addConstr( quicksum(Y[s, i, u, t - 1] for i in my_previous_v) == X[s, u, t])
def add_capture_constraints(md, g, my_vars: dict, searchers: dict, vertices_t, b0: list, M: list, deadline: int): """Define constraints about belief and capture events :param vertices_t: :param md: :param g: :param my_vars: :param searchers: :param b0 :param deadline """ # capture-related variables beta = get_var(my_vars, 'beta') alpha = get_var(my_vars, 'alpha') psi = get_var(my_vars, 'psi') false_neg, zeta = cm.check_false_negatives(searchers) # if false negative model, there will exist a delta if false_neg: delta = get_var(my_vars, 'delta') beta_s = get_var(my_vars, 'beta_s') else: delta = {} beta_s = {} # searchers position X = get_var(my_vars, 'x') # sets V = ext.get_set_vertices(g)[0] S, m = ext.get_set_searchers(searchers) Tau = ext.get_set_time(deadline) V_ext = ext.get_set_vertices_u_0(g) # initial belief (user input), t = 0 (Eq. 13) for i in V_ext: md.addConstr(beta[i, 0] == b0[i]) for t in Tau: # this is a dictionary my_vertices = cm.get_current_vertices(t, vertices_t, S) for v in V: # v_idx = ext.get_python_idx(v) # take Markovian model into account (Eq. 14) # NOTE M matrix is accessed by python indexing md.addConstr(alpha[v, t] == quicksum(M[u - 1][v - 1] * beta[u, t - 1] for u in V)) # find searchers position that could capture the target while it is in v list_u_capture = cm.get_u_for_capture(searchers, V, v) if list_u_capture and my_vertices: if false_neg: for s in S: md.addConstr( quicksum( X[s, u, t] for u in filter(lambda x: x in my_vertices[ s], list_u_capture)) >= psi[s, v, t]) md.addConstr( quicksum( X[s, u, t] for u in filter(lambda x: x in my_vertices[ s], list_u_capture)) <= psi[s, v, t]) else: md.addConstr( quicksum( quicksum(X[s, u, t] for u in filter( lambda x: x in my_vertices[s], list_u_capture)) for s in S) >= psi[v, t]) md.addConstr( quicksum( quicksum(X[s, u, t] for u in filter( lambda x: x in my_vertices[s], list_u_capture)) for s in S) <= m * psi[v, t]) if false_neg: for s in S: # first searcher if s == S[0]: md.addConstr(beta_s[0, v, t] == alpha[v, t]) # Eq. (38) md.addConstr(delta[s, v, t] <= 1 - psi[s, v, t]) # Eq. (39) md.addConstr(delta[s, v, t] <= beta_s[s - 1, v, t]) # Eq. (40) md.addConstr( delta[s, v, t] >= beta_s[s - 1, v, t] - psi[s, v, t]) # Eq. (37) md.addConstr(beta_s[s, v, t] == ((1 - zeta) * delta[s, v, t]) + (zeta * beta_s[s - 1, v, t])) # last searcher md.addConstr(beta[v, t] == beta_s[S[-1], v, t]) else: # (15) md.addConstr(beta[v, t] <= 1 - psi[v, t]) # (16) md.addConstr(beta[v, t] <= alpha[v, t]) # (17) md.addConstr(beta[v, t] >= alpha[v, t] - psi[v, t]) # probability of being intercepted == what is left md.addConstr(beta[0, t] == 1 - quicksum(beta[v, t] for v in V))
def add_target_variables(md, g, deadline: int, searchers=None): """Add variables related to the target and capture events: belief variable, B interception-related variables: belief vector composition, beta belief evolution, alpha capture event, zeta and psi """ # TODO change this to allow for different zetas (and unit-test it) V = ext.get_set_vertices(g)[0] T_ext = ext.get_set_time_u_0(deadline) T = ext.get_set_time(deadline) V_ext = ext.get_set_vertices_u_0(g) var_for_test = {} list_beta_name = [] list_alpha_name = [] list_delta_name = [] [beta, beta_s, alpha, psi, delta] = ext.init_dict_variables(5) if searchers is not None: false_neg, zeta = cm.check_false_negatives(searchers) S = ext.get_set_searchers(searchers)[0] else: false_neg = False S = None # alpha and psi: only exist from 1, 2.., T for t in T: for v in V: dummy_a_name = "[%d,%d]" % (v, t) alpha[v, t] = md.addVar(vtype="CONTINUOUS", lb=0.0, ub=1.0, name="alpha" + dummy_a_name) list_alpha_name.append(dummy_a_name) if false_neg: for s in S: dummy_delta_name = "[%d,%d,%d]" % (s, v, t) psi[s, v, t] = md.addVar(vtype="BINARY", name="psi" + dummy_delta_name) delta[s, v, t] = md.addVar(vtype="CONTINUOUS", lb=0.0, ub=1.0, name="delta" + dummy_delta_name) list_delta_name.append(dummy_delta_name) else: psi[v, t] = md.addVar(vtype="BINARY", name="psi" + dummy_a_name) for t in T_ext: for v in V_ext: dummy_b_name = "[%d,%d]" % (v, t) list_beta_name.append(dummy_b_name) beta[v, t] = md.addVar(vtype="CONTINUOUS", lb=0.0, ub=1.0, name="beta" + dummy_b_name) if false_neg: # include 0 for searcher s = 1, s-1 = 0 for s_ in [0] + S: dummy_bs_name = "[%d,%d,%d]" % (s_, v, t) beta_s[s_, v, t] = md.addVar(vtype="CONTINUOUS", lb=0.0, ub=1.0, name="beta_s" + dummy_bs_name) var_for_test.update({'beta': list_beta_name}) var_for_test.update({'alpha': list_alpha_name}) if false_neg: my_vars = { 'beta': beta, 'beta_s': beta_s, 'alpha': alpha, 'psi': psi, 'delta': delta } var_for_test.update({'delta': list_delta_name}) else: my_vars = {'beta': beta, 'alpha': alpha, 'psi': psi} return my_vars, var_for_test
def get_vertices_and_steps_distributed(G, deadline, searchers, temp_s_path): """Extract information from the user provided graph and information on searchers For each time step, find which vertices each searcher is allowed to be Since this is the distributed version, use info on temporary searchers path (temp_s_path)""" start = ext.get_searchers_positions(searchers) # S_ and Tau S, m = ext.get_set_searchers(start) Tau = ext.get_set_time(deadline) # get vertices V, n = ext.get_set_vertices(G) # shortest path lengths spl = ext.get_length_short_paths(G) # find V^tau(t) = {v in V} --> possible v(t) in optimal solution vertices_t = {} # find V^tau(v) = {t in Tau} --> possible t(v) in optimal solution times_v = {} for s in S: # initial position vertices_t[s, 0] = [temp_s_path[(s, 0)]] st_idx = ext.get_python_idx(vertices_t.get((s, 0))[0]) # starting at t = 1 (idx = 1), it begins to move for t in Tau: vertices_t[s, t] = [] if s == temp_s_path['current_searcher']: # if it's planning for this searcher, consider all possibilities # find the nodes that are within t of distance (thus can be reached at t) for v in V: v_idx = ext.get_python_idx(v) dummy_var = spl[st_idx][v_idx] if dummy_var <= t: vertices_t[s, t].append(v) else: # if is not the planning searcher, just use the info on the temporary path # either the start vertex of the pre-computed path v = temp_s_path[s, t] vertices_t[s, t].append(v) # find times allowed for each vertex for v in V: times_v[s, v] = [] if v == vertices_t[s, 0][0]: times_v[s, v] = [0] for t in Tau: if v in vertices_t[s, t]: times_v[s, v].append(t) # find dummy goal vertex and T + 1 v_g = ext.get_label_dummy_goal(V) t_g = ext.get_last_t(Tau) # append dummy goal vertices_t[s, t_g] = [v_g] # at T + 1, searcher is at dummy goal vertex times_v[s, v_g] = [ t_g ] # the only time allowed for the dummy goal vertex is T + 1 return start, vertices_t, times_v