Skip to content

Commit

Permalink
Format Attaques & cout par voies toggleable
Browse files Browse the repository at this point in the history
  • Loading branch information
Fur0rem committed Feb 13, 2024
1 parent c613833 commit 3539dd1
Showing 1 changed file with 162 additions and 155 deletions.
317 changes: 162 additions & 155 deletions scripts/Strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,169 +8,176 @@
# Juste pour test pour l'instant
ville="Saints"

def random_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""Each time, it removes a random edge from the graph until the budget is reached or no more edges are available"""

attacks = Attack(graph)
edges = list(graph.edges())

for time in range(nbTimes) :
edges_t = edges.copy()
budget_used = 0
nb_retires = 0
while budget_used < budget and len(edges_t) > 0 :
edge_idx = random.randint(0, graph.nb_edges() - (nb_retires + 1))
cost = graph.get_nb_lanes_of_edge(edge_idx)
if cost <= budget - budget_used :
attacks.add_attack(time, edge_idx)
budget_used += cost
nb_retires += 1
edges_t.pop(edge_idx)

return attacks

def sorted_attack(graph : CityGraph, nbTimes : int, budget : int, sort_by : callable) -> Attack :
"""Each time, it removes the edge that is the most affected by the sort_by function until the budget is reached or no more edges are available"""

attacks = Attack(graph)
edges = list(graph.edges())
for i, edge in enumerate(edges) :
edges[i] = graph.find_edge_index(edge[0], edge[1])
edges.sort(key = sort_by, reverse = True)

for time in range(nbTimes) :
edges_t = edges.copy()
budget_used = 0
nb_retires = 0
while budget_used < budget and len(edges_t) > 0 :
edge_idx = edges_t.pop(0)
cost = graph.get_nb_lanes_of_edge(edge_idx)
if cost <= budget - budget_used :
attacks.add_attack(time, edge_idx)
budget_used += cost
nb_retires += 1
edges_t.pop(edge_idx)

return attacks

def min_lanes_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""Each time, it removes the edge with the least lanes until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : -graph.get_nb_lanes_of_edge(x))

def max_lanes_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""Each time, it removes the edge with the most lanes until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : graph.get_nb_lanes_of_edge(x))

def betweenness_centralities_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""Each time, it removes the edge with the highest betweenness centrality until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : graph.get_edge_betweenness_centrality(x))

def moving_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""We start with random edges, and then with each time the attacks are moved to a neighbor edge"""
edges = list(graph.edges())

# First time
attacks = random_attack(graph, 1, budget)

# Next times
# First, find the neighbours of the concerned edges
# To find the neighbours, we find the edges connected to either of the nodes of the edge
neighbours = {}
for edge_idx in range(graph.nb_edges()) :
edge = graph.get_edge_at(edge_idx)
neighbours[edge_idx] = set()
for node in edge :
for edge2 in graph.graph.edges(node) :
neighbours[edge_idx].add(graph.find_edge_index(edge2[0], edge2[1]))

# Remove the edge itself from it's neighbours
for (k, v) in neighbours.items():
if k in v:
v.remove(k)

# Move the people around, but only add the attack if all the lanes are occupied
nb_people_on_edges = [0 for _ in range(graph.nb_edges())]
for attack in attacks.attacks :
nb_people_on_edges[attack[1]] += graph.get_nb_lanes_of_edge(attack[1])

print(nb_people_on_edges)


for time in range(1, nbTimes) :
for edge_idx in range(graph.nb_edges()) :
if nb_people_on_edges[edge_idx] > 0 :
# Move the people

# If there are no neighbours, stay on the edge
if len(neighbours[edge_idx]) == 0 :
attacks.add_attack(time, edge_idx)
continue

edge_idx2 = random.choice(list(neighbours[edge_idx]))
nb_people_on_edges[edge_idx] -= graph.get_nb_lanes_of_edge(edge_idx)
nb_people_on_edges[edge_idx2] += graph.get_nb_lanes_of_edge(edge_idx)
# Add the attack if all the lanes are occupied, dont move if not enough or already full
if nb_people_on_edges[edge_idx2] >= graph.get_nb_lanes_of_edge(edge_idx2) :
attacks.add_attack(time, edge_idx2)
nb_people_on_edges[edge_idx2] -= graph.get_nb_lanes_of_edge(edge_idx2)
nb_people_on_edges[edge_idx] += graph.get_nb_lanes_of_edge(edge_idx)
else :
attacks.add_attack(time, edge_idx)

# Add the last attack
for edge_idx in range(graph.nb_edges()) :
if nb_people_on_edges[edge_idx] > 0 :
attacks.add_attack(nbTimes, edge_idx)


return attacks

def is_bridge(graph : CityGraph, node0 : int, node1 : int) -> bool :
"""Returns True if the edge is a bridge"""
# TODO : ca marche pas pour les graphes orientes car networkx veut me rendre malheureux
# Remove the edge
graph.graph.remove_edge(node0, node1)
# Check if the graph is still connected
is_connected = nx.is_connected(graph.graph)
# Add the edge back
graph.graph.add_edge(node0, node1)
return not is_connected
def random_attack(graph : CityGraph, nbTimes : int, budget : int, costPerLane : bool) -> Attack :
"""Each time, it removes a random edge from the graph until the budget is reached or no more edges are available"""

costFunc = graph.get_nb_lanes_of_edge if costPerLane else lambda x : 1

attacks = Attack(graph)
edges = list(graph.edges())

for time in range(nbTimes) :
edges_t = edges.copy()
budget_used = 0
nb_retires = 0
while budget_used < budget and len(edges_t) > 0 :
edge_idx = random.randint(0, graph.nb_edges() - (nb_retires + 1))
cost = costFunc(edge_idx)
if cost <= budget - budget_used :
attacks.add_attack(time, edge_idx)
budget_used += cost
nb_retires += 1
edges_t.pop(edge_idx)

return attacks

def sorted_attack(graph : CityGraph, nbTimes : int, budget : int, sort_by : callable, costPerLane : bool) -> Attack :
"""Each time, it removes the edge that is the most affected by the sort_by function until the budget is reached or no more edges are available"""

costFunc = graph.get_nb_lanes_of_edge if costPerLane else lambda x : 1

attacks = Attack(graph)
edges = list(graph.edges())
for i, edge in enumerate(edges) :
edges[i] = graph.find_edge_index(edge[0], edge[1])
edges.sort(key = sort_by, reverse = True)

for time in range(nbTimes) :
edges_t = edges.copy()
budget_used = 0
nb_retires = 0
while budget_used < budget and len(edges_t) > 0 :
edge_idx = edges_t.pop(0)
cost = costFunc(edge_idx)
if cost <= budget - budget_used :
attacks.add_attack(time, edge_idx)
budget_used += cost
nb_retires += 1
edges_t.pop(edge_idx)

return attacks

def min_lanes_attack(graph : CityGraph, nbTimes : int, budget : int, costPerLane : bool) -> Attack :
"""Each time, it removes the edge with the least lanes until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : -graph.get_nb_lanes_of_edge(x), costPerLane)

def max_lanes_attack(graph : CityGraph, nbTimes : int, budget : int), costPerLane : bool -> Attack :
"""Each time, it removes the edge with the most lanes until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : graph.get_nb_lanes_of_edge(x), costPerLane)

def betweenness_centralities_attack(graph : CityGraph, nbTimes : int, budget : int, costPerLane : bool) -> Attack :
"""Each time, it removes the edge with the highest betweenness centrality until the budget is reached or no more edges are available"""
return sorted_attack(graph, nbTimes, budget, lambda x : graph.get_edge_betweenness_centrality(x), costPerLane)

def moving_attack(graph : CityGraph, nbTimes : int, budget : int, costPerLane : bool) -> Attack :
"""We start with random edges, and then with each time the attacks are moved to a neighbor edge"""

costFunc = graph.get_nb_lanes_of_edge if costPerLane else lambda x : 1
edges = list(graph.edges())

# First time
attacks = random_attack(graph, 1, budget)

# Next times
# First, find the neighbours of the concerned edges
# To find the neighbours, we find the edges connected to either of the nodes of the edge
neighbours = {}
for edge_idx in range(graph.nb_edges()) :
edge = graph.get_edge_at(edge_idx)
neighbours[edge_idx] = set()
for node in edge :
for edge2 in graph.graph.edges(node) :
neighbours[edge_idx].add(graph.find_edge_index(edge2[0], edge2[1]))

# Remove the edge itself from it's neighbours
for (k, v) in neighbours.items():
if k in v:
v.remove(k)

# Move the people around, but only add the attack if all the lanes are occupied
nb_people_on_edges = [0 for _ in range(graph.nb_edges())]
for attack in attacks.attacks :
nb_people_on_edges[attack[1]] += costFunc(attack[1])

print(nb_people_on_edges)


for time in range(1, nbTimes) :
for edge_idx in range(graph.nb_edges()) :
if nb_people_on_edges[edge_idx] > 0 :
# Move the people

# If there are no neighbours, stay on the edge
if len(neighbours[edge_idx]) == 0 :
attacks.add_attack(time, edge_idx)
continue

edge_idx2 = random.choice(list(neighbours[edge_idx]))
nb_people_on_edges[edge_idx] -= costFunc(edge_idx)
nb_people_on_edges[edge_idx2] += costFunc(edge_idx)
# Add the attack if all the lanes are occupied, dont move if not enough or already full
if nb_people_on_edges[edge_idx2] >= costFunc(edge_idx2) :
attacks.add_attack(time, edge_idx2)
nb_people_on_edges[edge_idx2] -= costFunc(edge_idx2)
nb_people_on_edges[edge_idx] += costFunc(edge_idx)
else :
attacks.add_attack(time, edge_idx)

# Add the last attack
for edge_idx in range(graph.nb_edges()) :
if nb_people_on_edges[edge_idx] > 0 :
attacks.add_attack(nbTimes, edge_idx)


return attacks


def connex_attack(graph : CityGraph, nbTimes : int, budget : int) -> Attack :
"""We remove edges which cut the graph into two parts recursively
Algorithm reference : https://stackoverflow.com/questions/11218746/bridges-in-a-connected-graph"""

attacks = Attack(graph)
edges = list(graph.edges())

# Find the bridge with the highest betweenness centrality
# Then remove it
for time in range(nbTimes) :
# Find the bridge with the highest betweenness centrality
bridge = None
max_betweenness = 0
for edge_idx in range(graph.nb_edges()) :
edge = graph.get_edge_at(edge_idx)
if is_bridge(graph, edge[0], edge[1]) :
betweenness = graph.get_edge_betweenness_centrality(edge_idx)
if betweenness > max_betweenness :
bridge = edge_idx
max_betweenness = betweenness
if bridge is not None :
attacks.add_attack(time, bridge)
else :
break

print_suppression_edge(graph, bridge)

return attacks
"""We remove edges which cut the graph into two parts recursively
Algorithm reference : https://stackoverflow.com/questions/11218746/bridges-in-a-connected-graph"""


def is_bridge(graph : CityGraph, node0 : int, node1 : int) -> bool :
"""Returns True if the edge is a bridge"""
# TODO : ca marche pas pour les graphes orientes car networkx veut me rendre malheureux
# Remove the edge
graph.graph.remove_edge(node0, node1)
# Check if the graph is still connected
is_connected = nx.is_connected(graph.graph)
# Add the edge back
graph.graph.add_edge(node0, node1)
return not is_connected

attacks = Attack(graph)
edges = list(graph.edges())

# Find the bridge with the highest betweenness centrality
# Then remove it
for time in range(nbTimes) :
# Find the bridge with the highest betweenness centrality
bridge = None
max_betweenness = 0
for edge_idx in range(graph.nb_edges()) :
edge = graph.get_edge_at(edge_idx)
if is_bridge(graph, edge[0], edge[1]) :
betweenness = graph.get_edge_betweenness_centrality(edge_idx)
if betweenness > max_betweenness :
bridge = edge_idx
max_betweenness = betweenness
if bridge is not None :
attacks.add_attack(time, bridge)
else :
break

print_suppression_edge(graph, bridge)

return attacks

graph = CityGraph(ville)
graph.print_stats()
# graph.show() # je sais pas comment fermer une fenetre sous sway au secours

a = random_attack(graph, 10, 10)
a = random_attack(graph, 10, 10, True)
a.write_to_file("test_random_attack.txt")
# a = min_lanes_attack(graph, 10, 10)
# a.write_to_file("test_min_lanes_attack.txt")
Expand Down

0 comments on commit 3539dd1

Please sign in to comment.