Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

✈️ Flight Route Optimizer

A modular flight route optimization system that models a real-world airline network as a directed weighted graph and computes optimal flight paths using Dijkstra's algorithm and A-star search.

The project combines real-world aviation data processing, graph modeling, shortest-path optimization, algorithm benchmarking, command-line interaction, automated testing, and interactive geographic visualization into a single application.

Rather than being a standalone implementation of a shortest-path algorithm, the system provides an end-to-end workflow:

OpenFlights Raw Data
        │
        ▼
Data Conversion
        │
        ▼
Structured JSON Data
        │
        ▼
Data Loading
        │
        ▼
Graph Construction
        │
        ▼
Weighted Flight Graph
        │
        ├───────────────┐
        ▼               ▼
    Dijkstra           A*
        │               │
        └───────┬───────┘
                ▼
          Optimal Route
                │
        ┌───────┴────────┐
        ▼                ▼
    Rich CLI       Folium HTML Map

The application allows users to search airports, calculate optimal routes, compare algorithm performance, inspect route details, and generate an interactive map of the resulting flight path.


📸 Project Preview

Main Menu

Main Menu

The application provides a terminal-based interface for accessing all major features of the system.

Available operations include:

  • Finding an optimal route
  • Searching airports
  • Benchmarking Dijkstra and A*
  • Generating an interactive route map

Route Search Result

Route Result

The route search displays:

  • Departure airport
  • Destination airport
  • Flight segments
  • Airlines
  • Segment distances
  • Total route cost
  • Selected algorithm
  • Number of visited nodes
  • Execution time

Alternative Route Result

Route Result Details

The application reconstructs the complete path returned by the shortest-path algorithm and presents each flight segment individually.


Algorithm Benchmark

Algorithm Benchmark

The benchmark system compares Dijkstra and A* using multiple performance metrics, including:

  • Average execution time
  • Visited nodes
  • Total route cost
  • Number of airports in the resulting path
  • Number of flight segments
  • Relative speedup

Interactive Route Map

Interactive Route Map

The generated route can also be visualized geographically using Folium.

The visualization is exported as an HTML document and can be opened directly in a web browser.


📖 Overview

Flight Route Optimizer represents an airline network as a directed weighted graph.

Each airport is modeled as a graph vertex, while each flight connection is represented as a directed edge.

The edge weight is the geographic distance between the connected airports.

For example:

IKA → DXB → LHR → JFK

represents a sequence of flight connections from Tehran Imam Khomeini International Airport to John F. Kennedy International Airport.

For a selected departure and destination airport, the system searches the graph and returns the minimum-distance route.

The resulting route contains:

  • Ordered airport sequence
  • Individual flight segments
  • Airline information
  • Geographic distances
  • Total route cost
  • Algorithm statistics

🌍 Data Source

The aviation data used by this project is based on the public OpenFlights Database.

Official dataset:

https://openflights.org/data.html

OpenFlights provides publicly available aviation data containing information such as:

  • Airports
  • Airport names
  • IATA codes
  • ICAO codes
  • Cities
  • Countries
  • Geographic coordinates
  • Airlines
  • Airline codes
  • Flight routes

The original raw dataset is stored in:

data/raw/
├── airports.dat
└── routes.dat

The project includes a conversion script that transforms the raw OpenFlights data into structured JSON files used by the application.

The processed data is stored in:

data/
├── airports.json
├── flights.json
└── airlines.json

The conversion process can be represented as:

OpenFlights .dat files
        │
        ▼
scripts/convert_dataset.py
        │
        ▼
Structured JSON datasets
        │
        ▼
Application DataLoader

This separation keeps raw external data independent from the application's internal data representation.


🧩 Data Pipeline

The complete data pipeline consists of several stages.

1. Raw Dataset

The project starts with OpenFlights airport and route data.

airports.dat
routes.dat

2. Dataset Conversion

The conversion script processes the raw files and creates structured JSON data.

scripts/convert_dataset.py

The resulting files are easier for the application to load and validate.


3. Data Loading

DataLoader reads the processed JSON files and converts them into application-level objects.

Airport records become Airport objects.

Route records become Route objects.


4. Graph Construction

GraphBuilder transforms the loaded airport and route information into the internal graph representation.

The resulting graph contains:

  • Airport nodes
  • Directed route edges
  • Edge weights
  • Route metadata

🧮 Graph Model

The flight network is represented as:

G = (V, E)

where:

  • V represents airports
  • E represents flight connections

The graph is directed because a route from airport A to airport B does not necessarily imply an identical route from B to A.

It is also weighted because every connection has a numerical cost.

In this implementation:

edge weight = geographic distance

Therefore, the shortest-path problem becomes:

Find the path between two airports that minimizes the total geographic distance.


✈️ Airport Nodes

Each airport is represented by an Airport object containing information such as:

IATA code
ICAO code
Airport name
City
Country
Latitude
Longitude

Example:

IKA
Imam Khomeini International Airport
Tehran
Iran
35.4161
51.1522

The geographic coordinates are particularly important because they are used both for:

  • Distance calculation
  • A* heuristic estimation
  • Interactive map visualization

🛫 Flight Route Edges

Each flight connection is represented by a Route object.

A route contains information such as:

Source airport
Destination airport
Airline code
Airline name
Geographic distance
Route cost

The route connects two airport nodes in the graph.

For example:

IKA → DXB

may represent a directed edge from Tehran to Dubai.


🌐 Geographic Distance

The project calculates geographic distances between airports using their latitude and longitude coordinates.

The implementation uses the geographic relationship between two points on the Earth rather than treating the coordinates as ordinary Cartesian points.

This distance serves two purposes:

  1. It becomes the edge cost used by the shortest-path algorithms.
  2. It provides the heuristic value used by A*.

This makes the geographic information an integral part of the optimization process rather than merely a visualization feature.


🚀 Shortest Path Algorithms

The system implements two shortest-path algorithms:

  • Dijkstra's Algorithm
  • A Search*

Both algorithms operate on the same graph and optimize the same cost function.

This allows their results and performance to be compared directly.


1. Dijkstra's Algorithm

Overview

Dijkstra's algorithm finds the shortest path from a starting node to other nodes in a weighted graph with non-negative edge weights.

In this project:

Node = Airport
Edge = Flight Route
Weight = Geographic Distance

The algorithm therefore searches for the minimum-distance flight path.


Core Idea

Dijkstra maintains a tentative distance for each airport.

Initially:

distance[start] = 0

and:

distance[all other nodes] = ∞

A priority queue is used to efficiently select the airport with the smallest currently known distance.

At every iteration:

  1. Extract the airport with the smallest tentative distance.
  2. Inspect its outgoing flight routes.
  3. Calculate the new distance to each neighboring airport.
  4. Update the neighbor if a shorter path has been discovered.
  5. Continue until the destination is reached or no reachable nodes remain.

The update operation is commonly known as relaxation.

For an edge:

u → v

the algorithm checks whether:

distance[u] + weight(u,v) < distance[v]

If this condition holds, the distance to v is improved.


Path Reconstruction

Dijkstra does not only store the shortest distance.

For every improved node, the algorithm stores information about its predecessor.

This allows the final path to be reconstructed after reaching the destination.

For example:

IKA
 ↓
DXB
 ↓
LHR
 ↓
JFK

The algorithm can reconstruct both:

Airport path

and:

Flight route segments

Why Dijkstra Is Correct

Dijkstra relies on the fact that all edge weights are non-negative.

When the algorithm extracts the node with the smallest tentative distance, no future path through another unprocessed node can produce a cheaper route to that node.

Therefore, once a node is finalized, its shortest distance is known.

This property guarantees optimality for the cost function used in this project.


Dijkstra Complexity

Let:

V = number of airports
E = number of flight routes

With an adjacency-list graph representation and a binary heap priority queue:

Time Complexity:
O((V + E) log V)

Space complexity:

O(V + E)

for the graph and algorithmic auxiliary structures.


2. A* Search Algorithm

Overview

A* is a heuristic shortest-path algorithm that combines:

g(n)

the actual cost accumulated from the starting airport, with:

h(n)

an estimate of the remaining cost to the destination.

Its evaluation function is:

f(n) = g(n) + h(n)

In this project:

g(n) = distance traveled from the start

while:

h(n) = estimated geographic distance to the destination

🧭 A* Heuristic

The main difference between A* and Dijkstra is the heuristic.

Dijkstra effectively behaves like A* with:

h(n) = 0

Therefore, it has no information about where the destination is beyond the graph structure itself.

A* introduces geographic information.

For an airport n, the heuristic estimates how far that airport is from the destination.

Because the edge cost is also based on geographic distance, this heuristic is naturally related to the optimization objective.


🔍 Why the Geographic Heuristic Is Useful

Consider searching for a route from:

Tehran → New York

Dijkstra explores the network according to accumulated distance from Tehran.

It does not explicitly prioritize airports that are geographically closer to New York.

A* considers both:

distance already traveled

and:

estimated distance remaining

Therefore, an airport that is geographically promising for reaching the destination can receive a higher search priority.

This can dramatically reduce the number of airports explored.


✅ A* Optimality

For A* to guarantee an optimal solution, the heuristic must satisfy the required admissibility conditions.

In a geographic-distance formulation, the straight-line/geodesic distance between the current airport and the destination provides a lower bound on the distance of any route connecting them, assuming the graph edge costs are geographic distances.

Therefore, the heuristic does not overestimate the remaining geographic travel distance.

This allows A* to retain optimality while potentially exploring substantially fewer nodes than Dijkstra.


⚙️ A* Search Process

At every iteration, A* prioritizes nodes according to:

f(n) = g(n) + h(n)

where:

g(n)

is the known route cost from the source, and:

h(n)

is the estimated remaining cost.

The search therefore balances:

What has already been traveled
+
What is estimated to remain

When the destination is reached under the appropriate priority conditions, the resulting route is optimal.


📊 A* Complexity

The exact practical performance of A* depends heavily on the quality of its heuristic.

In the worst case, A* can perform similarly to Dijkstra.

With a priority queue and adjacency-list representation, the worst-case complexity is:

O((V + E) log V)

The practical advantage comes from reducing the amount of the graph that must be explored.

Therefore, the most important performance difference between the two algorithms in this project is often:

Number of visited nodes

rather than a fundamentally different worst-case asymptotic complexity.


⚖️ Dijkstra vs A*

Both algorithms solve the same optimization problem and should return the same optimal route when configured with the same cost function.

Their search strategies are different.

Property Dijkstra A*
Shortest path Yes Yes
Uses heuristic No Yes
Uses geographic information As edge cost As edge cost + heuristic
Destination guidance No Yes
Optimal with current cost model Yes Yes, with valid heuristic
Worst-case complexity O((V+E) log V) O((V+E) log V)
Typical search space Larger Often smaller
Main advantage Generality and simplicity Goal-directed search

The important practical observation is that A* can reach the same optimal solution while examining substantially fewer nodes.


📈 Algorithm Benchmarking

The project includes a dedicated benchmarking component for experimentally comparing the algorithms.

Each algorithm is executed multiple times for the same:

Start Airport
Destination Airport
Graph
Cost Function

The benchmark calculates the average execution time to reduce the effect of individual runtime fluctuations.


Benchmark Metrics

Average Execution Time

Measures the average time required to compute the route.

Average Time

Visited Nodes

Measures how many graph nodes were processed during the search.

This is particularly important when comparing Dijkstra and A* because it shows how effectively the heuristic reduces the search space.


Route Cost

Represents the total geographic distance of the resulting route.

Both algorithms should produce the same optimal cost when operating correctly.


Path Nodes

The number of airports contained in the final path.

For example:

IKA → DXB → LHR → JFK

contains:

4 nodes

Flight Segments

The number of individual flight connections.

The same example contains:

3 segments

Relative Speedup

The benchmark also reports relative performance compared with the fastest algorithm.

For example:

Dijkstra    0.007s
A*          0.001s

indicates that A* required substantially less execution time for that particular query.

Benchmark results are dependent on:

  • Start and destination airports
  • Graph structure
  • Machine hardware
  • Python runtime
  • System load
  • Heuristic effectiveness

Therefore, benchmark results should be interpreted as experimental measurements rather than universal performance guarantees.


🗺 Interactive Route Visualization

After calculating a route, the application can generate an interactive geographic visualization using Folium.

The generated file is:

route_map.html

The output is a complete HTML document and can be opened directly in a web browser without requiring the application to remain running.


Map Features

The generated map contains:

  • Airport markers
  • Route lines
  • Geographic positioning
  • Airport information popups
  • Airline information
  • Segment distance
  • Segment cost
  • Interactive zoom
  • Pan/navigation
  • World map context

Each airport is displayed at its real geographic coordinates.

Each selected flight segment is represented by a line connecting the corresponding airports.

Additional information can be accessed through interactive map markers and popups.


🏗 Software Architecture

The project is organized into separate layers and modules so that data processing, graph logic, algorithms, user interaction, and visualization remain independent.

FlightRouteOptimizer/
│
├── assets/
│   └── screenshots/
│       ├── main.png
│       ├── route_result1.png
│       ├── route_result2.png
│       ├── benchmark.png
│       └── route_map.png
│
├── data/
│   ├── raw/
│   │   ├── airports.dat
│   │   └── routes.dat
│   │
│   ├── airports.json
│   ├── flights.json
│   └── airlines.json
│
├── scripts/
│   └── convert_dataset.py
│
├── src/
│   ├── algorithms/
│   │   ├── dijkstra.py
│   │   └── astar.py
│   │
│   ├── analytics/
│   │   └── benchmark.py
│   │
│   ├── core/
│   │   ├── data_loader.py
│   │   ├── geo.py
│   │   ├── graph.py
│   │   └── graph_builder.py
│   │
│   ├── exceptions/
│   │   ├── data_error.py
│   │   └── route_error.py
│   │
│   ├── models/
│   │   ├── airport.py
│   │   └── route.py
│   │
│   ├── services/
│   │   ├── graph_service.py
│   │   ├── route_service.py
│   │   └── search_service.py
│   │
│   ├── ui/
│   │   ├── airport_selector.py
│   │   ├── application.py
│   │   ├── colors.py
│   │   ├── menu.py
│   │   └── route_printer.py
│   │
│   └── visualization/
│       └── map.py
│
├── tests/
│
├── conftest.py
├── main.py
├── requirements.txt
├── .gitignore
└── README.md

🧩 Core Components

DataLoader

Responsible for loading the structured datasets and converting raw records into application-level objects.

Main responsibilities:

  • Loading airport data
  • Loading route data
  • Loading airline information
  • Validating input
  • Creating Airport and Route objects

GraphBuilder

Responsible for transforming the loaded aviation data into the graph representation.

It:

  • Adds airport nodes
  • Creates directed edges
  • Associates route metadata with edges
  • Calculates geographic distances
  • Handles invalid or incomplete route records

Graph

Provides the core graph representation used by the algorithms.

It manages:

  • Airport nodes
  • Route adjacency
  • Neighbor lookup
  • Airport existence checks
  • Graph-level operations

The algorithms operate on this abstraction rather than directly manipulating the raw dataset.


Geographic Utilities

The geographic module provides distance calculations based on airport coordinates.

This functionality is shared by:

  • Graph construction
  • A* heuristic calculation
  • Route analysis
  • Map visualization support

Route Service

The route service provides a higher-level interface for route optimization.

It handles:

  • Algorithm selection
  • Route search
  • Result processing
  • Path reconstruction
  • Returning structured route results

This keeps the UI independent from the internal implementation of individual algorithms.


Airport Search

The airport selection system supports searching by:

  • IATA code
  • Airport name
  • City
  • Country

It also provides a list of frequently connected airports to simplify route selection.


Route Printer

The CLI presentation layer formats route results using Rich.

It displays:

  • Journey summary
  • Departure airport
  • Destination airport
  • Flight path
  • Airlines
  • Distances
  • Total cost
  • Algorithm
  • Visited nodes
  • Execution time

RouteMap

The visualization module converts the calculated route into an interactive Folium map.

It is responsible for:

  • Creating the map
  • Positioning airports
  • Adding airport markers
  • Drawing route segments
  • Adding segment information
  • Exporting the result to HTML
  • Opening the generated map in the browser

🔄 End-to-End Execution Flow

A typical route search follows this sequence:

User selects departure airport
        ↓
User selects destination airport
        ↓
User selects Dijkstra or A*
        ↓
RouteService receives request
        ↓
Selected algorithm searches Graph
        ↓
Shortest path is reconstructed
        ↓
Route result is returned
        ↓
RoutePrinter displays result
        ↓
User can generate interactive map
        ↓
Folium creates route_map.html

This separates user interaction from graph processing and algorithm implementation.


🧪 Testing

The project includes automated tests for important core components.

The test suite covers areas such as:

  • Dijkstra correctness
  • A* correctness
  • Graph behavior
  • Geographic calculations
  • Data loading

Run the complete test suite with:

pytest

The purpose of the test suite is to verify that changes to individual components do not silently break the route optimization pipeline.


⚙️ Installation

Clone the repository:

git clone https://github.com/AradCharon/FlightRouteOptimizer.git

Move into the project directory:

cd FlightRouteOptimizer

Install dependencies:

pip install -r requirements.txt

🚀 Running the Application

Start the application with:

python main.py

The main menu provides:

[1] Find Optimal Route

[2] Search Airport

[3] Benchmark Algorithms

[4] Generate Route Map

[0] Exit

🔎 Finding an Optimal Route

Select:

[1] Find Optimal Route

The application then requests:

Departure Airport
Destination Airport
Algorithm

The user can select airports from the popular-airport list or search for an airport.

After selecting an algorithm, the application computes the route and displays the complete result.


📊 Benchmarking Algorithms

Select:

[3] Benchmark Algorithms

Choose:

Start Airport
Destination Airport

The system then executes both:

Dijkstra
A*

and reports their performance.

A typical benchmark may look like:

Algorithm   Avg Time    Visited   Cost       Nodes   Segments
Dijkstra    0.007084s   1,632     11,096.88  5       4
A*          0.001363s   61        11,096.88  5       4

The exact values depend on the selected airports and execution environment.


🗺 Generating a Route Map

After finding a route, select:

[4] Generate Route Map

The application creates:

route_map.html

The HTML file can be opened directly in a browser and provides an interactive geographic representation of the calculated route.


🛠 Technologies

  • Python 3
  • Graph Theory
  • Dijkstra's Algorithm
  • A Search*
  • Priority Queues / Heap
  • JSON
  • Folium
  • Rich
  • Pytest
  • Git
  • GitHub

🔬 Engineering Highlights

The project brings together several components into a single working system:

Real-World Data Integration

Uses publicly available aviation data rather than an artificial toy graph.

Graph Modeling

Transforms an airline network into a directed weighted graph suitable for shortest-path optimization.

Algorithmic Optimization

Implements both uninformed and heuristic-guided shortest-path search.

Heuristic Search

Uses geographic information to guide A* toward the destination.

Experimental Benchmarking

Measures actual algorithm behavior using execution time and graph exploration statistics.

Modular Architecture

Separates:

Data
Graph
Algorithms
Services
UI
Visualization
Testing

into independent modules.

Interactive Visualization

Transforms algorithm output into a browser-based geographic visualization.

Automated Testing

Provides tests for core algorithmic and data-processing components.


🔮 Future Roadmap

Potential extensions to the system include:

  • Multi-criteria route optimization
  • Ticket-price optimization
  • Travel-time optimization
  • Combined distance/time/cost optimization
  • Airline preference constraints
  • Number-of-stops constraints
  • Live flight data integration
  • Database-backed storage
  • REST API
  • Web-based frontend
  • Advanced geographic visualization
  • Weather-aware routing
  • Real-time route updates

These extensions could transform the current shortest-distance optimization system into a more comprehensive airline route planning platform.


👨‍💻 Author

Arad Shafiee

Interested in:

  • Artificial Intelligence
  • Machine Learning
  • Data Mining
  • Algorithms
  • Software Engineering

GitHub:

https://github.com/AradCharon


⭐ Repository

If you find this project interesting, consider giving it a star ⭐.

About

A Python-based flight route optimization system using graph algorithms, Dijkstra, A*, and interactive Folium map visualization.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages