graph: Adjust calculation to match exercise
This commit is contained in:
29
classes.py
29
classes.py
@@ -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:
|
||||||
|
|||||||
77
dijkstra.py
77
dijkstra.py
@@ -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
19
dijsktra.py
Normal 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
133
graph.py
Normal 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
|
||||||
9
main.py
9
main.py
@@ -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__":
|
||||||
|
|||||||
@@ -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...")
|
||||||
|
|||||||
Reference in New Issue
Block a user