From bca121e272b688bdf9e63b47f1657110d3a45591 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Mon, 2 Dec 2024 19:34:11 +0100 Subject: [PATCH] feat: :sparkles: Push notebook --- .idea/.gitignore | 8 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/test.iml | 10 + graphs.ipynb | 682 ++++++++++++++++++ 6 files changed, 720 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/test.iml create mode 100644 graphs.ipynb diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..722330d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..51ab974 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/test.iml b/.idea/test.iml new file mode 100644 index 0000000..d92f935 --- /dev/null +++ b/.idea/test.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/graphs.ipynb b/graphs.ipynb new file mode 100644 index 0000000..412e2a9 --- /dev/null +++ b/graphs.ipynb @@ -0,0 +1,682 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-12-02T17:41:32.959657Z", + "start_time": "2024-12-02T17:41:32.951161Z" + } + }, + "source": [ + "# -*- coding: utf-8 -*-\n", + "\"\"\"Graph module.\n", + "\n", + "Provide an implementation of graphs with adjacency lists.\n", + "\n", + "In a graph, vertices are considered numbered from 0 to the order of the graph\n", + "minus one. The vertex key can then be used to access its\n", + "adjacency list.\n", + "\n", + "\"\"\"\n", + "\n", + "\n", + "class Graph:\n", + " \"\"\" Simple class for graph: adjacency lists\n", + "\n", + " Attributes:\n", + " order (int): Number of vertices.\n", + " directed (bool): True if the graph is directed. False otherwise.\n", + " adjlists (List[List[int]]): Lists of connected vertices for each vertex.\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self, order, directed, labels=None):\n", + " \"\"\"Init graph, allocate adjacency lists\n", + "\n", + " Args:\n", + " order (int): Number of nodes.\n", + " directed (bool): True if the graph is directed. False otherwise.\n", + " labels (list[str]): optionnal vector of vertex labels\n", + " \"\"\"\n", + "\n", + " self.order = order\n", + " self.directed = directed\n", + " self.adjlists = []\n", + " for _ in range(order):\n", + " self.adjlists.append([])\n", + " self.labels = labels\n", + "\n", + " def addedge(self, src, dst):\n", + " \"\"\"Add egde to graph.\n", + "\n", + " Args:\n", + " src (int): Source vertex.\n", + " dst (int): Destination vertex.\n", + "\n", + " Raises:\n", + " IndexError: If any vertex index is invalid.\n", + "\n", + " \"\"\"\n", + " if src >= self.order or src < 0:\n", + " raise IndexError(\"Invalid src index\")\n", + " if dst >= self.order or dst < 0:\n", + " raise IndexError(\"Invalid dst index\")\n", + "\n", + " self.adjlists[src].append(dst)\n", + " if not self.directed and dst != src:\n", + " self.adjlists[dst].append(src)\n", + "\n", + "\n", + " def addvertex(self, number=1, labels=None):\n", + " \"\"\"Add number vertices to graph.\n", + "\n", + " Args:\n", + " ref (Graph).\n", + " number (int): Number of vertices to add.\n", + "\n", + " \"\"\"\n", + "\n", + " # Increment order and extend adjacency list\n", + " self.order += number\n", + " for _ in range(number):\n", + " self.adjlists.append([])\n", + " if labels:\n", + " self.labels += labels\n", + "\n", + " def removeedge(self, src, dst):\n", + " \"\"\"Remove egde from the graph.\n", + "\n", + " Args:\n", + " src (int): Source vertex.\n", + " dst (int): Destination vertex.\n", + "\n", + " Raises:\n", + " IndexError: If any vertex index is invalid.\n", + "\n", + " \"\"\"\n", + "\n", + " if src >= self.order or src < 0:\n", + " raise IndexError(\"Invalid src index\")\n", + " if dst >= self.order or dst < 0:\n", + " raise IndexError(\"Invalid dst index\")\n", + " if dst in self.adjlists[src]:\n", + " self.adjlists[src].remove(dst)\n", + " if not self.directed and dst != src:\n", + " self.adjlists[dst].remove(src)\n", + "\n", + "def sortgraph(G):\n", + " \"\"\"\n", + " sorts adjacency lists -> to have same results as those asked in tutorials/exams\n", + " \"\"\"\n", + " for i in range(G.order):\n", + " G.adjlists[i].sort()\n", + "\n", + "def dot(G):\n", + " \"\"\"Dot format of graph.\n", + "\n", + " Args:\n", + " Graph\n", + "\n", + " Returns:\n", + " str: String storing dot format of graph.\n", + "\n", + " \"\"\"\n", + "\n", + " if G.directed:\n", + " s = \"digraph {\\n\"\n", + " for x in range(G.order):\n", + " if G.labels:\n", + " s += \" \" + str(x) + '[label = \"' + G.labels[x] + '\"]\\n'\n", + " else:\n", + " s += \" \" + str(x) + '\\n'\n", + " for y in G.adjlists[x]:\n", + " s += str(x) + \" -> \" + str(y) + '\\n'\n", + " else:\n", + " s = \"graph {\\n\"\n", + " for x in range(G.order):\n", + " if G.labels:\n", + " s += \" \" + str(x) + '[label = \"' + G.labels[x] + '\"]\\n'\n", + " else:\n", + " s += \" \" + str(x) + '\\n'\n", + " for y in G.adjlists[x]:\n", + " if x <= y:\n", + " s += str(x) + \" -- \" + str(y) + '\\n'\n", + " return s + '}'\n", + "\n", + "def display(G, eng=None):\n", + " \"\"\"\n", + " *Warning:* Made for use within IPython/Jupyter only.\n", + " eng: graphivz.Source \"engine\" optional argument (try \"neato\", \"fdp\", \"sfdp\", \"circo\")\n", + "\n", + " \"\"\"\n", + "\n", + " try:\n", + " from graphviz import Source\n", + " from IPython.display import display\n", + " except:\n", + " raise Exception(\"Missing module: graphviz and/or IPython.\")\n", + " display(Source(dot(G), engine = eng))\n", + "\n", + "\n", + "# load / save gra format\n", + "\n", + "def load(filename):\n", + " \"\"\"Build a new graph from a GRA file.\n", + "\n", + " Args:\n", + " filename (str): File to load.\n", + "\n", + " Returns:\n", + " Graph: New graph.\n", + "\n", + " Raises:\n", + " FileNotFoundError: If file does not exist.\n", + "\n", + " \"\"\"\n", + "\n", + " f = open(filename)\n", + " lines = f.readlines()\n", + " f.close()\n", + "\n", + " infos = {}\n", + " i = 0\n", + " while '#' in lines[i]:\n", + " (key, val) = lines[i][1:].strip().split(\": \")\n", + " infos[key] = val\n", + " i += 1\n", + "\n", + " directed = bool(int(lines[i]))\n", + " order = int(lines[i+1])\n", + "\n", + " if infos and \"labels\" in infos:\n", + " labels = infos[\"labels\"].split(',') #labels is a list of str\n", + " G = Graph(order, directed, labels) # a graph with labels\n", + " else:\n", + " G = Graph(order, directed) # a graph without labels\n", + " if infos:\n", + " G.infos = infos\n", + "\n", + " for line in lines[i+2:]:\n", + " edge = line.strip().split(' ')\n", + " (src, dst) = (int(edge[0]), int(edge[1]))\n", + " G.addedge(src, dst)\n", + " return G\n", + "\n", + "\n", + "def save(G, fileOut):\n", + " gra = \"\"\n", + " if G.labels:\n", + " lab = \"#labels: \"\n", + " for i in range(G.order - 1):\n", + " lab += G.labels[i] + ','\n", + " lab += G.labels[-1]\n", + " gra += lab + '\\n'\n", + " gra += str(int(G.directed)) + '\\n'\n", + " gra += str(G.order) + '\\n'\n", + " for x in range(G.order):\n", + " for y in G.adjlists[x]:\n", + " if G.directed or x >= y:\n", + " gra += str(x) + \" \" + str(y) + '\\n'\n", + " fout = open(fileOut, mode='w')\n", + " fout.write(gra)\n", + " fout.close()\n" + ], + "outputs": [], + "execution_count": 2 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T17:41:47.620425Z", + "start_time": "2024-12-02T17:41:47.614349Z" + } + }, + "cell_type": "code", + "source": [ + "# -*- coding: utf-8 -*-\n", + "\"\"\"Graph module.\n", + "\n", + "Provide an implementation of graphs with adjacency matrix.\n", + "This can also be called static implementation.\n", + "\n", + "In a graph, vertices are considered numbered from 0 to the order of the graph\n", + "minus one.\n", + "\n", + "\"\"\"\n", + "\n", + "\n", + "class GraphMat:\n", + " \"\"\" Simple class for static graph.\n", + "\n", + " Attributes:\n", + " order (int): Number of vertices.\n", + " directed (bool): True if the graph is directed. False otherwise.\n", + " adj (List[List[int]]): Adjacency matrix\n", + " \"\"\"\n", + "\n", + " def __init__(self, order, directed):\n", + " \"\"\"\n", + " Args:\n", + " order (int): Number of nodes.\n", + " directed (bool): True if the graph is directed. False otherwise.\n", + " \"\"\"\n", + "\n", + " self.order = order\n", + " self.directed = directed\n", + " self.adj = [[0 for j in range(order)] for i in range(order)]\n", + "\n", + "\n", + " def addedge(self, src, dst):\n", + " \"\"\"Add egde to graph.\n", + "\n", + " Args:\n", + " src (int): Source vertex.\n", + " dst (int): Destination vertex.\n", + "\n", + " Raises:\n", + " IndexError: If any vertex index is invalid.\n", + "\n", + " \"\"\"\n", + "\n", + " if src >= self.order or src < 0:\n", + " raise IndexError(\"Invalid src index\")\n", + " if dst >= self.order or dst < 0:\n", + " raise IndexError(\"Invalid dst index\")\n", + "\n", + " self.adj[src][dst] += 1\n", + " if not self.directed and dst != src:\n", + " self.adj[dst][src] += 1\n", + "\n", + "\n", + "\n", + "def dot(G):\n", + " \"\"\"Dot format of graph.\n", + "\n", + " Args:\n", + " GraphMat\n", + "\n", + " Returns:\n", + " str: String storing dot format of graph.\n", + "\n", + " \"\"\"\n", + "\n", + " if G.directed:\n", + " s = \"digraph {\\n\"\n", + " link = \" -> \"\n", + " for x in range(G.order):\n", + " for y in range(G.order):\n", + " s += (str(x) + link + str(y) + '\\n') * G.adj[x][y]\n", + " else:\n", + " s = \"graph {\\n\"\n", + " link = \" -- \"\n", + " for x in range(G.order):\n", + " for y in range(x+1):\n", + " s += (str(x) + link + str(y) + '\\n') * G.adj[x][y]\n", + " return s + '}'\n", + "\n", + "\n", + "\n", + "def display(G, eng=None):\n", + " \"\"\"\n", + " *Warning:* Made for use within IPython/Jupyter only.\n", + " eng: graphivz.Source \"engine\" optional argument (try \"neato\", \"fdp\", \"sfdp\", \"circo\")\n", + "\n", + " \"\"\"\n", + "\n", + " try:\n", + " from graphviz import Source\n", + " from IPython.display import display\n", + " except:\n", + " raise Exception(\"Missing module: graphviz and/or IPython.\")\n", + " display(Source(dot(G), engine = eng))\n", + "\n", + "\n", + "# load / save gra format (do not manage labels and other infos)\n", + "\n", + "def load(filename,):\n", + " \"\"\"Build a new graph from a GRA file.\n", + "\n", + " Args:\n", + " filename (str): File to load.\n", + "\n", + " Returns:\n", + " Graph: New graph.\n", + "\n", + " Raises:\n", + " FileNotFoundError: If file does not exist.\n", + "\n", + " \"\"\"\n", + "\n", + " f = open(filename)\n", + " directed = bool(int(f.readline()))\n", + " order = int(f.readline())\n", + " g = GraphMat(order, directed)\n", + " for line in f.readlines():\n", + " edge = line.strip().split(' ')\n", + " (src, dst) = (int(edge[0]), int(edge[1]))\n", + " g.addedge(src, dst)\n", + " f.close()\n", + " return g\n", + "\n", + "def save(G, fileOut):\n", + " gra = str(int(G.directed)) + '\\n'\n", + " gra += str(G.order) + '\\n'\n", + " for x in range(G.order):\n", + " if G.directed:\n", + " n = G.order\n", + " else:\n", + " n = x + 1\n", + " for y in range(n):\n", + " for i in range(G.adj[x][y]):\n", + " gra += str(x) + \" \" + str(y) + '\\n'\n", + " fout = open(fileOut, mode='w')\n", + " fout.write(gra)\n", + " fout.close()\n" + ], + "id": "e12f5903c5348752", + "outputs": [], + "execution_count": 3 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Graph figure 2", + "id": "52a4e079fe9cea35" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T17:44:49.997870Z", + "start_time": "2024-12-02T17:44:49.994811Z" + } + }, + "cell_type": "code", + "source": [ + "G = Graph(10, False)\n", + "G.adjlists = [[4, 4, 1, 3],\n", + " [0],\n", + " [6, 6, 6, 5, 7],\n", + " [0],\n", + " [0, 0, 9],\n", + " [2, 7, 8],\n", + " [2, 2, 2, 7],\n", + " [2, 6, 5, 8],\n", + " [7, 5, 8],\n", + " [4]]\n", + "\n" + ], + "id": "ca54f5a3f1a225b", + "outputs": [], + "execution_count": 9 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T17:46:47.125622Z", + "start_time": "2024-12-02T17:46:47.122992Z" + } + }, + "cell_type": "code", + "source": [ + "print(G.order)\n", + "print(G.adjlists)\n", + "print(G.adjlists[1])\n" + ], + "id": "45b4722e0e0844c6", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10\n", + "[[4, 4, 1, 3], [0], [6, 6, 6, 5, 7], [0], [0, 0, 9], [2, 7, 8], [2, 2, 2, 7], [2, 6, 5, 8], [7, 5, 8], [4]]\n", + "[0]\n" + ] + } + ], + "execution_count": 16 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Graph Figure 1", + "id": "7b374e3cdb9f773c" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T17:57:16.222216Z", + "start_time": "2024-12-02T17:57:16.219422Z" + } + }, + "cell_type": "code", + "source": [ + "G1 = Graph(9, True)\n", + "G1.adjlists = [[4, 1, 1, 1, 5, 3],\n", + " [4],\n", + " [3],\n", + " [6, 6],\n", + " [],\n", + " [4, 2, 0],\n", + " [0, 5],\n", + " [8, 1, 0],\n", + " [6, 8]]\n" + ], + "id": "6920c423c0bdfc24", + "outputs": [], + "execution_count": 22 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Exercise 1.3", + "id": "313f1375b01bcce1" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T17:56:13.875386Z", + "start_time": "2024-12-02T17:56:13.870731Z" + } + }, + "cell_type": "code", + "source": [ + "def degrees(G):\n", + " final = []\n", + " for element in G.adjlists:\n", + " final.append(len(element))\n", + " return final\n", + "\n", + "degrees(G)" + ], + "id": "55ba6e30c008762e", + "outputs": [ + { + "data": { + "text/plain": [ + "[4, 1, 5, 1, 3, 3, 4, 4, 3, 1]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 21 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T18:17:29.691716Z", + "start_time": "2024-12-02T18:17:29.688234Z" + } + }, + "cell_type": "code", + "source": [ + "def in_out_degrees(G):\n", + " In = [0] * G.order\n", + " Out = [0] * G.order\n", + " for i in range(G.order):\n", + " for element in G.adjlists[i]:\n", + " In[element] += 1\n", + " Out[i] += 1\n", + " return [In, Out]\n", + "\n", + "in_out_degrees(G1)" + ], + "id": "1b1a1615d90dc209", + "outputs": [ + { + "data": { + "text/plain": [ + "[[3, 4, 1, 2, 3, 2, 3, 0, 2], [6, 1, 1, 2, 0, 3, 2, 3, 2]]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 24 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Exercise 1.4", + "id": "4bd26fbd65135589" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-12-02T18:22:10.123287Z", + "start_time": "2024-12-02T18:22:10.119678Z" + } + }, + "cell_type": "code", + "source": [ + "def dot(G):\n", + " string = \"digraph {\\n\"\n", + " if G.directed:\n", + " for i in range(G.order):\n", + " for element in G.adjlists[i]:\n", + " string += f\"{i} --> {element}\\n\"\n", + " elif not G.directed:\n", + " for i in range(G.order):\n", + " for element in G.adjlists[i]:\n", + " string += f\"{i} -- {element}\\n\"\n", + " string += \"}\"\n", + " return string\n", + "\n", + "print(dot(G1))\n", + "print(dot(G))" + ], + "id": "f7602fcf61e82a17", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "digraph {\n", + "0 --> 4\n", + "0 --> 1\n", + "0 --> 1\n", + "0 --> 1\n", + "0 --> 5\n", + "0 --> 3\n", + "1 --> 4\n", + "2 --> 3\n", + "3 --> 6\n", + "3 --> 6\n", + "5 --> 4\n", + "5 --> 2\n", + "5 --> 0\n", + "6 --> 0\n", + "6 --> 5\n", + "7 --> 8\n", + "7 --> 1\n", + "7 --> 0\n", + "8 --> 6\n", + "8 --> 8\n", + "}\n", + "digraph {\n", + "0 -- 4\n", + "0 -- 4\n", + "0 -- 1\n", + "0 -- 3\n", + "1 -- 0\n", + "2 -- 6\n", + "2 -- 6\n", + "2 -- 6\n", + "2 -- 5\n", + "2 -- 7\n", + "3 -- 0\n", + "4 -- 0\n", + "4 -- 0\n", + "4 -- 9\n", + "5 -- 2\n", + "5 -- 7\n", + "5 -- 8\n", + "6 -- 2\n", + "6 -- 2\n", + "6 -- 2\n", + "6 -- 7\n", + "7 -- 2\n", + "7 -- 6\n", + "7 -- 5\n", + "7 -- 8\n", + "8 -- 7\n", + "8 -- 5\n", + "8 -- 8\n", + "9 -- 4\n", + "}\n" + ] + } + ], + "execution_count": 31 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Exercise 2.1 (BFS)\n", + "id": "ebfdd54aefc25650" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "", + "id": "b8bf6413a1d63515" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Exercise 2.2 (DFS)", + "id": "55b1247fe428aa0d" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}