def test_braess_paradox(self): """Test that Braess paradox can be reproduced with the mean field game.""" num_player = 8 braess_network = dynamic_routing_utils.Network( { "O": "A", "A": ["B", "C"], "B": ["C", "D"], "C": ["D"], "D": ["E"], "E": [] }, node_position={ "O": (0, 0), "A": (1, 0), "B": (2, 1), "C": (2, -1), "D": (3, 0), "E": (4, 0) }, bpr_a_coefficient={ "O->A": 0, "A->B": 1.0, "A->C": 0, "B->C": 0, "B->D": 0, "C->D": 1.0, "D->E": 0 }, bpr_b_coefficient={ "O->A": 1.0, "A->B": 1.0, "A->C": 1.0, "B->C": 1.0, "B->D": 1.0, "C->D": 1.0, "D->E": 1.0 }, capacity={ "O->A": num_player, "A->B": num_player, "A->C": num_player, "B->C": num_player, "B->D": num_player, "C->D": num_player, "D->E": num_player }, free_flow_travel_time={ "O->A": 0, "A->B": 1.0, "A->C": 2.0, "B->C": 0.25, "B->D": 2.0, "C->D": 1.0, "D->E": 0 }) demand = [ dynamic_routing_utils.Vehicle("O->A", "D->E") for _ in range(num_player) ] game = dynamic_routing.DynamicRoutingGame( {"time_step_length": 0.125, "max_num_time_step": 40}, network=braess_network, vehicles=demand) class TruePathPolicy(policy.Policy): def __init__(self, game): super().__init__(game, list(range(num_player))) self._path = {} def action_probabilities(self, state, player_id=None): assert player_id is not None legal_actions = state.legal_actions(player_id) if not legal_actions: return {dynamic_routing_utils.NO_POSSIBLE_ACTION: 1.0} elif len(legal_actions) == 1: return {legal_actions[0]: 1.0} else: if legal_actions[0] == 2: if self._path[player_id] in ["top", "middle"]: return {2: 1.0} elif self._path[player_id] == "bottom": return {3: 1.0} else: raise ValueError() elif legal_actions[0] == 4: if self._path[player_id] == "top": return {5: 1.0} elif self._path[player_id] == "middle": return {4: 1.0} else: raise ValueError() raise ValueError(f"{legal_actions} is not correct.") class NashEquilibriumBraess(TruePathPolicy): def __init__(self, game): super().__init__(game) for player_id in range(num_player): if player_id % 2 == 0: self._path[player_id] = "middle" if player_id % 4 == 1: self._path[player_id] = "top" if player_id % 4 == 3: self._path[player_id] = "bottom" class SocialOptimumBraess(NashEquilibriumBraess): def __init__(self, game): super().__init__(game) for player_id in range(num_player): if player_id % 2 == 0: self._path[player_id] = "top" if player_id % 2 == 1: self._path[player_id] = "bottom" ne_policy = NashEquilibriumBraess(game) # TODO(cabannes): debug issue with nash conv computation and uncomment the # following line. # self.assertEqual(exploitability.nash_conv(game, ne_policy), 0.0) self.assertSequenceAlmostEqual( -expected_game_score.policy_value(game.new_initial_state(), ne_policy), [3.75] * num_player) so_policy = SocialOptimumBraess(game) # TODO(cabannes): debug issue with nash conv computation and uncomment the # following line. # self.assertEqual(exploitability.nash_conv(game, so_policy), 0.125) self.assertSequenceAlmostEqual( -expected_game_score.policy_value(game.new_initial_state(), so_policy), [3.5] * num_player)
def setUp(self): """Create a network O->A->D for testing.""" super().setUp() self.network = utils.Network({"O": ["A"], "A": ["D"], "D": []})
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Default data for dynamic routing game.""" from open_spiel.python.games import dynamic_routing_utils LINE_NETWORK = dynamic_routing_utils.Network({ "bef_O": "O", "O": ["A"], "A": ["D"], "D": ["aft_D"], "aft_D": [] }) LINE_NETWORK_VEHICLES_DEMAND = [ dynamic_routing_utils.Vehicle("bef_O->O", "D->aft_D") for _ in range(2) ] LINE_NETWORK_OD_DEMAND = [ dynamic_routing_utils.OriginDestinationDemand("bef_O->O", "D->aft_D", 0, 100) ] BRAESS_NUM_PLAYER = 5 BRAESS_NETWORK = dynamic_routing_utils.Network(
def create_braess_network(capacity): graph_dict = { "A": { "connection": { "B": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 0 } }, "location": [0, 0] }, "B": { "connection": { "C": { "a": 1.0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 1.0 }, "D": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 2.0 } }, "location": [1, 0] }, "C": { "connection": { "D": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 0.25 }, "E": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 2.0 } }, "location": [2, 1] }, "D": { "connection": { "E": { "a": 1, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 1.0 } }, "location": [2, -1] }, "E": { "connection": { "F": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": 0.0 } }, "location": [3, 0] }, "F": { "connection": {}, "location": [4, 0] } } adjacency_list = { key: list(value["connection"].keys()) for key, value in graph_dict.items() } bpr_a_coefficient = {} bpr_b_coefficient = {} capacity = {} free_flow_travel_time = {} for o_node, value_dict in graph_dict.items(): for d_node, section_dict in value_dict["connection"].items(): road_section = dynamic_routing_utils._nodes_to_road_section( origin=o_node, destination=d_node) bpr_a_coefficient[road_section] = section_dict["a"] bpr_b_coefficient[road_section] = section_dict["b"] capacity[road_section] = section_dict["capacity"] free_flow_travel_time[road_section] = section_dict[ "free_flow_travel_time"] node_position = { key: value["location"] for key, value in graph_dict.items() } return dynamic_routing_utils.Network( adjacency_list, node_position=node_position, bpr_a_coefficient=bpr_a_coefficient, bpr_b_coefficient=bpr_b_coefficient, capacity=capacity, free_flow_travel_time=free_flow_travel_time)
def create_sioux_falls_network(): sioux_falls_adjacency_list = {} sioux_falls_node_position = {} bpr_a_coefficient = {} bpr_b_coefficient = {} capacity = {} free_flow_travel_time = {} content = open("./SiouxFalls_node.csv", "r").read() for line in content.split("\n")[1:]: row = line.split(",") sioux_falls_node_position[row[0]] = [ int(row[1]) / 1e5, int(row[2]) / 1e5 ] sioux_falls_node_position[f"bef_{row[0]}"] = [ int(row[1]) / 1e5, int(row[2]) / 1e5 ] sioux_falls_node_position[f"aft_{row[0]}"] = [ int(row[1]) / 1e5, int(row[2]) / 1e5 ] sioux_falls_adjacency_list[f"bef_{row[0]}"] = [row[0]] sioux_falls_adjacency_list[row[0]] = [f"aft_{row[0]}"] sioux_falls_adjacency_list[f"aft_{row[0]}"] = [] bpr_a_coefficient[f"{row[0]}->aft_{row[0]}"] = 0.0 bpr_b_coefficient[f"{row[0]}->aft_{row[0]}"] = 1.0 capacity[f"{row[0]}->aft_{row[0]}"] = 0.0 free_flow_travel_time[f"{row[0]}->aft_{row[0]}"] = 0.0 bpr_a_coefficient[f"bef_{row[0]}->{row[0]}"] = 0.0 bpr_b_coefficient[f"bef_{row[0]}->{row[0]}"] = 1.0 capacity[f"bef_{row[0]}->{row[0]}"] = 0.0 free_flow_travel_time[f"bef_{row[0]}->{row[0]}"] = 0.0 content = open("./SiouxFalls_net.csv", "r").read() for l in content.split("\n")[1:-1]: _, origin, destination, a0, a1, a2, a3, a4 = l.split(",") assert all(int(x) == 0 for x in [a1, a2, a3]) sioux_falls_adjacency_list[origin].append(destination) road_section = f"{origin}->{destination}" bpr_a_coefficient[road_section] = float(a4) bpr_b_coefficient[road_section] = 4.0 capacity[road_section] = 1.0 free_flow_travel_time[road_section] = float(a0) sioux_falls_od_demand = [] content = open("./SiouxFalls_od.csv", "r").read() for line in content.split("\n")[1:-1]: row = line.split(",") sioux_falls_od_demand.append( dynamic_routing_utils.OriginDestinationDemand( f"bef_{row[0]}->{row[0]}", f"{row[1]}->aft_{row[1]}", 0, float(row[2]))) return dynamic_routing_utils.Network( sioux_falls_adjacency_list, node_position=sioux_falls_node_position, bpr_a_coefficient=bpr_a_coefficient, bpr_b_coefficient=bpr_b_coefficient, capacity=capacity, free_flow_travel_time=free_flow_travel_time), sioux_falls_od_demand
def create_series_parallel_network(num_network_in_series, time_step_length=1, capacity=1): i = 0 origin = "A_0->B_0" graph_dict = {} while i < num_network_in_series: tt_up = random.random() + time_step_length tt_down = random.random() + time_step_length graph_dict.update({ f"A_{i}": { "connection": { f"B_{i}": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": time_step_length } }, "location": [0 + 3 * i, 0] }, f"B_{i}": { "connection": { f"C_{i}": { "a": 1.0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": tt_up }, f"D_{i}": { "a": 1.0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": tt_down } }, "location": [1 + 3 * i, 0] }, f"C_{i}": { "connection": { f"A_{i+1}": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": time_step_length } }, "location": [2 + 3 * i, 1] }, f"D_{i}": { "connection": { f"A_{i+1}": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": time_step_length } }, "location": [2 + 3 * i, -1] } }) i += 1 graph_dict[f"A_{i}"] = { "connection": { "END": { "a": 0, "b": 1.0, "capacity": capacity, "free_flow_travel_time": time_step_length } }, "location": [0 + 3 * i, 0] } graph_dict["END"] = {"connection": {}, "location": [1 + 3 * i, 0]} time_horizon = int(3.0 * (num_network_in_series + 1) / time_step_length) destination = f"A_{i}->END" adjacency_list = { key: list(value["connection"].keys()) for key, value in graph_dict.items() } bpr_a_coefficient = {} bpr_b_coefficient = {} capacity = {} free_flow_travel_time = {} for o_node, value_dict in graph_dict.items(): for d_node, section_dict in value_dict["connection"].items(): road_section = dynamic_routing_utils._nodes_to_road_section( origin=o_node, destination=d_node) bpr_a_coefficient[road_section] = section_dict["a"] bpr_b_coefficient[road_section] = section_dict["b"] capacity[road_section] = section_dict["capacity"] free_flow_travel_time[road_section] = section_dict[ "free_flow_travel_time"] node_position = { key: value["location"] for key, value in graph_dict.items() } return dynamic_routing_utils.Network( adjacency_list, node_position=node_position, bpr_a_coefficient=bpr_a_coefficient, bpr_b_coefficient=bpr_b_coefficient, capacity=capacity, free_flow_travel_time=free_flow_travel_time ), origin, destination, time_horizon