diff --git a/create_graph_dumb.py b/create_graph_dumb.py
new file mode 100644
index 0000000000000000000000000000000000000000..d748761c4f3e2842a299a339473f3476b16e86d8
--- /dev/null
+++ b/create_graph_dumb.py
@@ -0,0 +1,73 @@
+import random
+import argparse
+
+
+def create_random_graph(args):
+    nb_nodes = args.nodes
+    nb_links = args.links
+
+    nodes = dict()
+    for _ in range(nb_links):
+        node_a = random.randint(0, nb_nodes - 1)
+        node_b = random.randint(0, nb_nodes - 1)
+        while node_b == node_a:
+            node_b = random.randint(0, nb_nodes - 1)
+        c_ab = random.randint(1, 10)
+
+        nodes.setdefault(node_a, list()).append((node_b, c_ab))
+
+    return nodes, nb_links
+
+
+def ntf_parse(args):
+    with open(args.ntf) as fd:
+        data = fd.read().split("\n")
+
+    mapping = dict()
+    nodes = dict()
+    for line in data:
+        tab = line.split(" ")
+        node_a = tab[0]
+        node_b = tab[1]
+
+        node_a = mapping.setdefault(node_a, len(mapping))
+        node_b = mapping.setdefault(node_b, len(mapping))
+        
+        c_ab = int(tab[2])
+        nodes.setdefault(node_a, list()).append((node_b, c_ab))
+
+    return nodes, len(data)
+
+
+def to_binary_file(nodes, nb_links, output):
+    nb_nodes = len(nodes)
+    with open(output, "wb+") as fd:
+        fd.write(nb_nodes.to_bytes(4, "big"))
+        fd.write(nb_links.to_bytes(4, "big"))
+
+        print(nodes)
+        for node in nodes:
+            for j, cost in nodes[node]:
+                fd.write(node.to_bytes(4, "big"))
+                fd.write(j.to_bytes(4, "big"))
+                fd.write(cost.to_bytes(4, "big"))
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--ntf", type=str, default=None,
+                        help="Parse an NTF file instead of creating a graph")
+    parser.add_argument("--output", type=str,
+                        help="Output file", default="graph.bin")
+    parser.add_argument("-n", "--nodes", type=int,
+                        help="Number of nodes. Unused if '--ntf'", default=5)
+    parser.add_argument("-l", "--links", type=int,
+                        help="Number of links. Unused if '--ntf'", default=10)
+    args = parser.parse_args()
+
+    if args.ntf:
+        graph, nb_links = ntf_parse(args)
+    else:
+        graph, nb_links = create_random_graph(args)
+
+    to_binary_file(graph, nb_links, args.output)
diff --git a/shortest_path.py b/shortest_path.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd1ba825c682c6d716ceffa8819a1ef890dc31a7
--- /dev/null
+++ b/shortest_path.py
@@ -0,0 +1,122 @@
+import numpy as np
+import math
+
+import argparse
+import sys
+import os
+
+
+
+parser = argparse.ArgumentParser(description="LEPL1503 - Détection et correction d'erreurs")
+parser.add_argument("input_file", help="Nom du fichier contenant les données nécessaires")
+parser.add_argument("-f", help="Chemin vers le fichier de sortie", type=argparse.FileType("wb"), default=sys.stdout)
+parser.add_argument("-v", help="\"verbose\" mode: si ajouté, affiche des informations sur l'exécution du programme", action="store_true")
+args = parser.parse_args()
+
+verbose = args.v
+output_fd = args.f
+nb_nodes = None
+nb_edges = None
+
+if verbose:
+    print(args, file=sys.stderr)
+
+def get_file_infos(data):
+    nb_nodes = int.from_bytes(data[0:4], "big",signed=True)
+    nb_edges = int.from_bytes(data[4:], "big",signed=True)
+    return nb_nodes,nb_edges
+
+def bellman_ford(table,s):
+    dist = [math.inf]*nb_nodes
+    dist[s]=0
+    path = [-1]*nb_nodes
+    for _ in range(nb_nodes-1):
+        for j in range(len(table)):
+            a,b,cab = table[j][0],table[j][1],table[j][2]
+            if(dist[a]!=math.inf and dist[b]>dist[a]+cab):
+                dist[b]=dist[a]+cab
+                path[b]=a
+    for j in range(len(table)):
+            a,b,cab = table[j][0],table[j][1],table[j][2]
+            if(dist[a]!=math.inf and dist[b]>dist[a]+cab):
+                print("Cycle négatif détecté")
+                return -1, -1
+    return dist, path
+
+def get_path(dest, path,source):
+    r = [dest]
+    i = dest
+    while(True):
+        if (i ==source):
+            break
+        r.insert(0,path[i])
+        i = path[i]
+    return r
+
+def get_max(dist,s):
+    max = -math.inf
+    n = s
+    for i in range(len(dist)):
+        if(i!=s and dist[i]!=math.inf and dist[i]>=max):
+            max = dist[i]
+            n=i
+    if(max==-math.inf):
+        if(dist[s]!=math.inf and dist[s]>=max):
+            max = dist[s]
+    
+    return max,n
+if __name__ == "__main__":
+    
+    with open(args.input_file, "rb") as input_file:
+        binary_data = input_file.read()
+        nb_nodes, nb_edges = get_file_infos(binary_data[:8])
+        if verbose:
+                print("Number of nodes :", nb_nodes, ", number of links :", nb_edges)
+        
+        binary_data = binary_data[8:]
+        table = []
+        if output_fd == sys.stdout or output_fd == sys.stderr:
+            print(nb_nodes)
+            
+        else : 
+            output_fd.write(nb_nodes.to_bytes(4, "big"))
+            
+
+        for i in range(nb_edges):
+            a = int.from_bytes(binary_data[i*16:i*16+4],"big",signed=True)
+            b = int.from_bytes(binary_data[i*16+4:i*16+8],"big",signed=True)
+            cab = int.from_bytes(binary_data[i*16+8:i*16+12],"big",signed=True)
+            cba = int.from_bytes(binary_data[i*16+12:i*16+16],"big",signed=True)
+            if (cab !=0):
+                l1 = [a,b,cab]
+                table.append(l1)
+            if(cba!=0):
+                l2 = [b,a,cba]
+                table.append(l2)
+        for i in range(nb_nodes):
+            dist, path = bellman_ford(table,i)
+            if dist ==-1 : break
+            
+            if output_fd == sys.stdout or output_fd == sys.stderr:
+                print("source : "+str(i))
+                d,n = get_max(dist,i)
+                print("destination : "+ str(n))
+                print("cout : "+ str(d))
+                p = get_path(n,path,i)
+                print("nombre de noeuds : "+str(len(p)))
+                print("chemin : "+" ".join(str(x) for x in p))
+                print("-----------------------")
+                
+            else : 
+                output_fd.write(i.to_bytes(4, "big"))
+                d,n = get_max(dist,i)
+                output_fd.write(n.to_bytes(4, "big",signed=True))
+                output_fd.write(d.to_bytes(4, "big",signed=True))
+                r = get_path(n,path,i)
+                output_fd.write(len(r).to_bytes(4, "big",signed=True))
+                for j in range(len(r)) : 
+                    output_fd.write(r[j].to_bytes(4, "big"))
+                
+
+
+        
\ No newline at end of file
diff --git a/verify_output.py b/verify_output.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8a7e655ef9a03b808b6df76cbb3f73f1bc7e549
--- /dev/null
+++ b/verify_output.py
@@ -0,0 +1,47 @@
+import argparse
+import struct
+
+
+def verify_output(file):
+    with open(file, "rb") as fd:
+        # First 4 bytes should be the number of nodes
+        data = fd.read(4)
+        nb_nodes, = struct.unpack(">l", data)
+
+        # The file should contain exactly nb_nodes entries
+        for _ in range(nb_nodes):
+            # An entry is 4 + 4 + 4 + 4 + len(path) * 4 bytes
+            data = fd.read(16)
+
+            # Index of the node, distance value, path length (number of hops)
+            source_idx, node_idx, a, path_len = struct.unpack(">llll", data)
+
+            # The node index lies within the limits.
+            assert source_idx >= 0 and source_idx < nb_nodes
+            assert node_idx >= 0 and node_idx < nb_nodes
+
+            # The path len can be nul if there is no path.
+            # The shortest path cannot contain loops.
+            assert path_len >= -1 and path_len < nb_nodes
+
+            if path_len > 0:
+                for _ in range(path_len):
+                    data = fd.read(4)
+                    hop_idx, = struct.unpack(">l", data)
+
+                    # Same... the node index lies within the limits.
+                    assert hop_idx >= 0 and hop_idx < nb_nodes
+
+        # The file does not contain anymore bytes
+        assert fd.read() == b""
+
+        print("The file has the correct format!\nThis does not mean that it solves the shortest path problem, but at least it contains readable information...")
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "file", type=str, help="Binary file generated by the project to inspect")
+    args = parser.parse_args()
+
+    verify_output(args.file)
diff --git a/visualize_graph.py b/visualize_graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..40558600d951aafff49da826fa415b56f048c69f
--- /dev/null
+++ b/visualize_graph.py
@@ -0,0 +1,44 @@
+import graphviz
+import struct
+import argparse
+import os
+
+
+def read_graph(filename):
+    with open(filename, "rb") as fd:
+        data = fd.read(8)
+        _, nb_links = struct.unpack(">ll", data)
+
+        graph = dict()
+
+        for _ in range(nb_links):
+            data = fd.read(12)
+            node_1, node_2, cost_12 = struct.unpack(">lll", data)
+            graph.setdefault(node_1, list()).append((node_2, cost_12))
+
+    return graph
+
+
+def plot_graph(graph, output_filepath):
+    file, file_extension = os.path.splitext(output_filepath)
+    g = graphviz.Graph(format=file_extension[1:])
+
+    for node in graph:
+        for nei_id, cost in graph[node]:
+            g.node(f"{node}", label=f"{node}")
+            g.node(f"{nei_id}", label=f"{nei_id}")
+            g.edge(f"{node}", f"{nei_id}", label=f"{cost}", dir="forward")
+
+    g.render(file)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "file", type=str, help="Input file (binary) representing the graph")
+    parser.add_argument("save", type=str,
+                        help="Save the graph visualization in the indicated path")
+    args = parser.parse_args()
+
+    graph = read_graph(args.file)
+    plot_graph(graph, args.save)