graph: Adjust calculation to match exercise

This commit is contained in:
Marco Thomas
2022-07-27 14:32:37 +02:00
parent 0b29bdab3d
commit d6a8689175
6 changed files with 183 additions and 90 deletions

View File

@@ -15,22 +15,33 @@ class LocationType(Enum):
class TransportData(): class TransportData():
def __init__(self, co2: float, speed: float, distance_penalty: float): def __init__(self, co2: float, speed: float):
self.co2 = co2 self.co2 = co2
self.speed = speed self.speed = speed
self.distance_penalty = distance_penalty
def __str__(self):
return f"{{co2: {self.co2}, speed: {self.speed}}}"
def __repr__(self):
return self.__str__()
class TransportMethod(Enum): class TransportMethod(Enum):
WALK = TransportData(0, 4)
CITY = TransportData(0.189, 30)
AUTOBAHN = TransportData(0.189, 100)
OEPNV = TransportData(0.055, 30)
ICE = TransportData(0.055, 100)
AIRPLANE = TransportData(0.2113, 900)
class TransportKind(Enum):
""" """
(co2 emission, speed, distance_penalty) distance_penalty
""" """
WALK = TransportData(0, 4, 0.2) INDIVIDUAL = 0.2
CITY = TransportData(0.189, 30, 0.2) TRAIN = 0.1
AUTOBAHN = TransportData(0.189, 100, 0.2) FLYING = 0.02
OEPNV = TransportData(0.055, 30, 0.1)
ICE = TransportData(0.055, 100, 0.1)
AIRPLANE = TransportData(0.2113, 900, 0.02)
class Coordinate: class Coordinate:

View File

@@ -1,77 +0,0 @@
"""
Module, which holds the logic for the solving algorithms
"""
from classes import DataSet, LocationType, Location, TransportMethod
def calc_co2(distance: float, method: TransportMethod) -> float:
"""
Return co2 emission in kg
"""
return (distance * method.value.distance_penalty) * method.value.co2
def calc_time(distance: float, method: TransportMethod) -> float:
"""
Return time taking in h
"""
return (distance * method.value.distance_penalty) / method.value.speed
def add_node(graph: dict, frm: str, to: str, locs: dict, method: TransportMethod):
"""
Add a node into the graph
"""
distance = locs[frm].distance(locs[to])
co2 = calc_co2(distance, method)
time = calc_time(distance, method)
new_connection: dict = {to: {"type": method, "co2": co2, "time": time}}
graph[frm].append(new_connection)
print(f"Added node from {frm} to {to} with type {method}.")
def create_graph(dataset: DataSet) -> dict:
"""
Creates the initial graph, with all edges
"""
locations = dataset.locations
graph: dict = {}
# add nodes with no edges
for start in locations:
graph.update({start: []})
# add edges
for start in locations:
for dest in locations:
# skip, if we wouldnt go anywhere
if start == dest:
continue
print(f"Searching for nodes from {start} to {dest}...")
distance = locations[start].distance(locations[dest])
# Individualtransport
if distance <= 1:
add_node(graph, start, dest, locations, TransportMethod.WALK)
if distance <= 10 + 1:
add_node(graph, start, dest, locations, TransportMethod.CITY)
if distance <= 2000 + 10 + 1:
add_node(graph, start, dest, locations, TransportMethod.AUTOBAHN)
# Train
if locations[start].type == LocationType.HALTESTELLE:
dest_type = locations[dest].type
# there are only trains between haltestellen or airports
if dest_type == LocationType.HALTESTELLE or dest_type == LocationType.FLUGHAFEN:
if distance <= 25:
add_node(graph, start, dest, locations, TransportMethod.OEPNV)
else:
add_node(graph, start, dest, locations, TransportMethod.ICE)
# Flying
flights = dataset.flights
for flight in flights:
add_node(graph, start, dest, locations, TransportMethod.AIRPLANE)
return graph

19
dijsktra.py Normal file
View File

@@ -0,0 +1,19 @@
"""
This module holds the logic for the solving
"""
class Dijkstra():
def __init__(self, graph: dict):
"""
table: matrix with vertex as key, price and prev vertex as value
OL: open list, to keep track of finished vertecis
"""
self.graph = graph
self.table = {}
self.OL = []
def algorithm(self):
print("Performing Dijkstra on the following graph...")
for vertex in self.graph:
print(f"{vertex}: {self.graph[vertex]}")

133
graph.py Normal file
View File

@@ -0,0 +1,133 @@
"""
Module, which creates a graph
"""
from classes import DataSet, LocationType, TransportMethod, TransportKind
def calc_co2(distance: float, kind: TransportKind) -> float:
"""
Return co2 emission in kg
"""
match kind:
case TransportKind.INDIVIDUAL:
if distance <= 1:
return 0
else:
# TODO: CITY == AUTOBAHN
return distance * TransportMethod.CITY.value.co2
case TransportKind.TRAIN:
# TODO: OPENV == ICE
return distance * TransportMethod.ICE.value.co2
case TransportKind.FLYING:
return distance * TransportMethod.AIRPLANE.value.co2
def calc_time(
distance: float,
kind: TransportKind,
flights: dict = None,
frm: dict = None,
) -> float:
"""
distance: distance without penalty
kind: kind of transport
flights: all flights (optional)
frm: start location (need for flights, optional)
"""
match kind:
case TransportKind.INDIVIDUAL:
distance += distance * TransportKind.INDIVIDUAL.value
if distance <= 1:
return distance / TransportMethod.WALK.value.speed
elif distance <= 10 + 1:
speed = 1 / TransportMethod.WALK.value.speed
return speed + ((distance - 1) / TransportMethod.CITY.value.speed)
elif distance < 2000 + 10 + 1:
speed = 1 / TransportMethod.WALK.value.speed
speed += 10 / TransportMethod.WALK.value.speed
return speed + ((distance - 1 - 10) / TransportMethod.AUTOBAHN.value.speed)
case TransportKind.TRAIN:
distance += distance * TransportKind.TRAIN.value
if distance <= 25:
return distance / TransportMethod.OEPNV.value.speed
else:
speed = 25 / TransportMethod.OEPNV.value.speed
# NOTE: should we subtract here?
return speed + ((distance - 25) / TransportMethod.ICE.value.speed)
case TransportKind.FLYING:
assert(flights != None)
assert(frm != None)
distance += distance * TransportKind.FLYING.value
stops = flights[frm]["stops"]
domestic = flights[frm]["domestic"]
if domestic:
time = 2
else:
time = 3
waittime = (stops + 1) * time
return waittime + (distance / TransportMethod.AIRPLANE.value.speed)
def create_graph(dataset: DataSet) -> dict:
"""
Creates the initial graph, with all edges
"""
locations = dataset.locations
graph: dict = {}
# add nodes with no edges
for start in locations:
graph.update({start: []})
# add edges
for start in locations:
for dest in locations:
# skip, if we wouldnt go anywhere
if start == dest:
continue
print(f"Searching for nodes from {start} to {dest}...")
distance = locations[start].distance(locations[dest])
# Individualtransport
if distance <= 2000 + 10 + 1:
time = calc_time(distance, TransportKind.INDIVIDUAL)
co2 = calc_co2(distance, TransportKind.INDIVIDUAL)
new_connection: dict = {dest:
{"kind": TransportKind.INDIVIDUAL,
"co2": co2,
"time": time}}
graph[start].append(new_connection)
print(f"Added new INDIVIDUAL connection from {start} to {dest}")
# Train
if locations[start].type == LocationType.HALTESTELLE:
dest_type = locations[dest].type
# there are only trains between haltestellen or airports
if dest_type == LocationType.HALTESTELLE or dest_type == LocationType.FLUGHAFEN:
time = calc_time(distance, TransportKind.TRAIN)
co2 = calc_co2(distance, TransportKind.TRAIN)
new_connection: dict = {dest:
{"kind": TransportKind.TRAIN,
"co2": co2,
"time": time}}
graph[start].append(new_connection)
print(f"Added new TRAIN connection from {start} to {dest}")
# Flying
print("Adding flights...")
flights = dataset.flights
for flight in flights:
start = flight
dest = flights[flight]["to"]
distance = locations[start].distance(locations[dest])
time = calc_time(distance, TransportKind.FLYING, flights, start)
co2 = calc_co2(distance, TransportKind.FLYING)
new_connection: dict = {dest:
{"kind": TransportKind.TRAIN,
"co2": co2,
"time": time}}
graph[start].append(new_connection)
print(f"Added new FLYING connection from {start} to {dest}")
return graph

View File

@@ -4,7 +4,8 @@ Requires: python > 3.10.x
""" """
from parser import parse from parser import parse
from dijkstra import create_graph from graph import create_graph
from dijsktra import Dijkstra
INPUTFILE = "file.txt" INPUTFILE = "file.txt"
@@ -12,9 +13,11 @@ INPUTFILE = "file.txt"
def main(): def main():
dataset: dict = parse(INPUTFILE) dataset: dict = parse(INPUTFILE)
print(dataset) # print(dataset)
graph: dict = create_graph(dataset) graph: dict = create_graph(dataset)
print(graph) # print(graph)
dijkstra = Dijkstra(graph)
dijkstra.algorithm()
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -68,7 +68,11 @@ def parse(filename: str) -> DataSet:
stops = splitted[2] stops = splitted[2]
else: else:
stops = 0 stops = 0
flights.update({id1: {"to": id2, "stops": stops}}) if len(splitted) == 4:
domestic = True
else:
domestic = False
flights.update({id1: {"to": id2, "stops": stops, "domestic": domestic}})
continue continue
case ParsingMode.FINDCONNECTION: case ParsingMode.FINDCONNECTION:
print("Parsing connection...") print("Parsing connection...")