From de655064565c25cf8f28bcf6e8643979599ccf53 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Jan 2025 09:16:35 +0000 Subject: [PATCH] [CS4423]: Add WK02-1 Jupyter notebook --- .../CS4423/materials/CS4423-W02-1.ipynb | 1106 +++++++++++++++++ 1 file changed, 1106 insertions(+) create mode 100644 year4/semester2/CS4423/materials/CS4423-W02-1.ipynb diff --git a/year4/semester2/CS4423/materials/CS4423-W02-1.ipynb b/year4/semester2/CS4423/materials/CS4423-W02-1.ipynb new file mode 100644 index 00000000..69393763 --- /dev/null +++ b/year4/semester2/CS4423/materials/CS4423-W02-1.ipynb @@ -0,0 +1,1106 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "toc": true + }, + "source": [ + "

Table of Contents

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# CS4423 : Week 02 - Lecture 1 - Networks [$\\color{red}{\\text{DRAFT}}$]\n", + "# More on Graphs, and `networkx`\n", + "\n", + "Niall Madden, \n", + "School of Mathematical and Statistical Sciences \n", + "University of Galway\n", + "\n", + "(These notes are adapted from Angela Carnevale's work)\n", + "\n", + "This notebook is at https://www.niallmadden.ie/2425-CS4423/W02/CS4423-W02-1.ipynb\n", + "You can read the HTML version at https://www.niallmadden.ie/2425-CS4423/W02/CS4423-W02-1.html\n", + "\n", + "
This version of this notebook was written by Niall Madden, adapted from notebooks by Angela Carnevale.
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## News: \n", + "### Labs\n", + "\n", + "Labs start next week, and an (reintroduction) to Python. This will run:\n", + "* Tuesday at 4 in AC215 (slight chance this might get moved to Tuesday at 3), and\n", + "* Wednesday at 10am in CA116a. \n", + "\n", + "These rooms are not labs: BYoD! (Bring Your Own Device)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Website\n", + "I now plan to post all notes to https://www.niallmadden.ie/2425-CS4423/ as well as to Canvas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## `networkx`\n", + "Last week we learned a little about the `networkx` package. We'll return to that now, while also revisiting some key ideas about graphs." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As ever, we'll start with importing the `networkx` module, as well as `numpy`: more about that later. And we'll define the `opts` option dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "import networkx as nx\n", + "import numpy as np\n", + "opts = { \"with_labels\": True, \"node_color\": 'y' } # show labels; yellow noodes" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "To create a graph with nodes $1$, $2$, $3$, $4$, $5$, and edges between all even and odd labelled nodes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "K32 = nx.Graph()\n", + "K32.add_edges_from([(1, 2), (1,4), (2,3), (2,5), (3,4), (4,5)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll later learn this is the graph $K_{3,2}$. Now draw it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "nx.draw(K32, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "We can also be lazy, and just give $2$-letter strings for the edges: this implicitly defines the nodes too. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "K33 = nx.Graph([\"A1\", \"A2\", \"A3\", \"B1\", \"B2\", \"B3\", \"C1\", \"C2\", \"C3\"])\n", + "nx.draw(K33, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Check basic properties:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"K33 has {K33.number_of_nodes()} nodes and {K33.number_of_edges()} edges\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "print(f\"This is the same as saying K33 order {K33.order()} and size {K33.size()}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To list the nodes and edges (as lists)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "list(K33.nodes)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "list(K33.edges)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "A **loop** over a graph `G` will effectively loop over `G`'s nodes. As an example, (recall?) that the **degree** of a node is the number of edges incident to it (or, if you prefer, the number of neighbours)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "for node in K33:\n", + " print(f\"node {node} has neighbours {list(K33.neighbors(node))}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Adding and removing nodes and edges\n", + "\n", + "We say that \n", + "* `G.add_node('v')` adds a node to $G$ called 'v'\n", + "* `G.add_nodes_from([2, 3, 5])` adds all the nodes from a list\n", + "* `G.add_nodes_from(H])` adds all the nodes from Graph $H$ to Graph $G$\n", + "* `G.add_edge('x','y')` add edge from Node $x$ to Node $y$, adding one or both nodes, if needed.\n", + "* `G.add_edges_from([(1,5), (2,5), (3,5)])` add edges from a list\n", + "* `G.add_edges_from(H.edges)` add edges from another graph\n", + "* `G.remove_edge('x','y')` remove edge from $x$ to $y$, but keep the nodes\n", + "* `G.remove_node('x')` remove node $x$ and any edge it was incident to." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Neighbours and degree\n", + "\n", + "(As we've seen) \n", + "* The neighbours of a node are those that it shares an edge with\n", + "* the degree of a node is the number of edges incident to it (or, if you prefer, the number of neighbours).\n", + "\n", + "Let's look at an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Edges1 = [('Aoife', 'Brian'), ('Aoife', 'Ciara'), ('Aoife', 'Daire'), ('Aoife', 'Ella'), \n", + " ('Aoife', 'Finn'), ('Brian', 'Ciara'), ('Brian', 'Finn'), ('Ciara', 'Daire'), \n", + " ('Daire', 'Ella'), ('Ella', 'Finn') ]\n", + "G1 = nx.Graph(Edges1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "nx.draw(G1, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "This is example, which is known as a *wheel graph\" is chosen because it exhibits a famous concept in Network Science: *The Friendship Paradox*: your friends (probably) have more friends, on average, than you do!\n", + "\n", + "Explanation:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "notes" + } + }, + "outputs": [], + "source": [ + "#pos = nx.nx_agraph.graphviz_layout(G1)\n", + "#nx.draw(G1, pos=pos,**opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Important Graphs\n", + "\n", + "In this section we'll discuss some important examples of graphs, which we'll return to later as key examples of networks. These include\n", + "* Complete Graphs\n", + "* Bipartite and complete bipartite graphs\n", + "* Path graphs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Complete Graphs\n", + "\n", + "The [**complete graph**](https://en.wikipedia.org/wiki/Complete_graph)\n", + "on a vertex set $X$ is the graph with edge set all of $\\binom{X}{2}$. That is: every node is a neighbour of every other node. It is denoted $K_n$ where $n=|X|$. E.g., if $X=\\{0,1,2,3\\}$, then $K_4$ (\"the complete graph on 4 nodes\") has edges $E=\\{01, 02, 03, 12, 13, 23\\}$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "nodes = range(4)\n", + "list(nodes)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "E4 = [(x, y) for x in nodes for y in nodes if x < y]\n", + "print(E4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "K4 = nx.Graph(E4)\n", + "nx.draw(K4)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "While it is somewhat straightforward to find all $2$-element\n", + "subsets of a given set $X$ with a short `python` program,\n", + "it is probably more convenient (and possibly efficient) to use a function from the\n", + "`itertools` package for this purpose." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "from itertools import combinations\n", + "nodes5 = range(5)\n", + "combinations(nodes5, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "print(list(combinations(nodes5, 2)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "K5 = nx.Graph(combinations(nodes5, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "nx.draw(K5, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "`networkx` has a built-in function to create complete graphs: `complete_graph` [[doc]](https://networkx.org/documentation/stable//reference/generated/networkx.generators.classic.complete_graph.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "nx.draw(nx.complete_graph(\"NETWORKS\"), **opts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "nx.draw(nx.complete_graph(22), **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Bipartite Graphs\n", + "\n", + "A graph is **bipartite** if we can divide the node set, $X$, into two subsets $X_1$ and $X_2$ such that \n", + "* $X_1 \\cap X_2 = \\emptyset$ (the sets have no edge in common)\n", + "* $X_1 \\cup X_2 = X$ \n", + "* For any edge $(u_1,u_2)$ we have $u_1 \\in X_1$ and $u_2 \\in X_2$. That is we only ever have edges between nodes from different sets. \n", + "\n", + "Such graphs are very common in Network Science, where nodes in the network represent two different types of entities. For example, we might have a graph where nodes represent students and modules, with edges between students and modules they are enrolled in (often called an affiliation network)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Edges2 = [('Aoife', 'CS4423'), ('Aoife', 'CS319'), ('Aoife', 'MA432'), \n", + " ('Brian', 'CS4423'), ('Brian', 'CS319'), \n", + " ('Ciara', 'CS319'), ('Ciara', 'MA432'), \n", + " ('Daire', 'MA432') ]\n", + "G2 = nx.Graph(Edges2)\n", + "nx.draw(G2, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Somehow that previous graph did not catch the essence of the network: there are two different types of node. We could make that clearer, by colouring the nodes. Here we'll do it manually (later, automatically)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "print(G2.nodes)\n", + "color_list= ['c','y','y','y','c', 'c','c'] # y=yellow; c=cyan\n", + "nx.draw(G2, node_color=color_list, with_labels=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Complete Bipartite Graphs\n", + "\n", + "A **complete bipartite graph** is a particular bipartite graph where there is an edge between every node in $X_1$ and every node in $X_2$. Such graphs are denoted $K_{m,n}$ where $|X_1|=m$ and $|X_2|=n$. (We met $K_{2,2}$ and $K_{3,3}$ earlier). \n", + "\n", + "As usual, there is a built-in generator: `complete_bipartite_graph` [[doc]](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.bipartite.generators.complete_bipartite_graph.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "K33 = nx.complete_bipartite_graph(3,3)\n", + "nx.draw(K33,**opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Path Graphs\n", + "\n", + "The **Path Graph** with $n$ nodes, denoted $P_n$, is one where two nodes have degree 1, and the other $n-2$ have degree 2:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "P4 = nx.Graph([\"ab\", \"bc\", \"cd\", \"de\"])\n", + "nx.draw(P4)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "The built-in `nerworkx`generator is called `path_graph` [[doc]](https://networkx.org/documentation/stable/reference/generated/networkx.generators.classic.path_graph.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "P10 = nx.path_graph(10)\n", + "nx.draw(P10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Cycle Graphs\n", + "\n", + "Our last example: the **cycle** graph, which as a path graph, but with an edge between the two \"end\" nodes. If it has $n$ nodes, we denote it $C_n$. You can make one with `cycle_graph(n)`, but here we'll do it manually.\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C5 = nx.Graph(['01', '12', '23', '34', '40'])\n", + "nx.draw(C5, **opts) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nx.draw(nx.cycle_graph(6))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Petersen Graph\n", + "\n", + "The [Petersen Graph](https://en.wikipedia.org/wiki/Petersen_graph)\n", + "is a graph on $10$ vertices with $15$ edges.\n", + "\n", + "It can be constructed \n", + "as the complement of the line graph of the complete graph $K_5$,\n", + "i.e.,\n", + "as the graph with vertex set\n", + "$$X = \\binom{\\{0,1,2,3,4\\}}{2}$$ (the edge set of $K_5$) and\n", + "with an edge between $x, y \\in X$ whenever $x \\cap y = \\emptyset$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "nx.draw(K5, **opts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "lines = K5.edges\n", + "print(list(lines))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "print(list(combinations(lines, 2)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "edges = [e for e in combinations(lines, 2) \n", + " if not set(e[0]) & set(e[1])]\n", + "len(edges)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "P = nx.Graph(edges)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "nx.draw(P, **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Even though there is no parameter involved in this example,\n", + "it might be worth wrapping the construction up into a `python`\n", + "function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "def petersen_graph():\n", + " nodes = combinations(range(5), 2)\n", + " G = nx.Graph()\n", + " for e in combinations(nodes, 2):\n", + " if not set(e[0]) & set(e[1]):\n", + " G.add_edge(*e)\n", + " return G" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "nx.draw(petersen_graph(), **opts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Code Corner" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### `python`" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "* **list unpacking** operator `*e`: if `e` is a list, an\n", + "argument `*e` passes the elements of `e` as individual arguments\n", + "to a function call." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "* **dictionary unpacking** operator `**opts`: `python` function calls take **positional** arguments and **keyword** arguments. The keyword arguments can be collected in a dictionary `opts` (with the keywords as keys). This dictionary can then be passed into the function call in its \"unwrapped\" form `**opts`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "* **set intersection**: if `a` and `b` are sets then `a & b` represents the intersection of `a` and `b`. In a boolean context, an empty set counts as `False`, and a non-empty set as `True`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "a = set([1,2,3])\n", + "b = set([3,4,5])\n", + "a & b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "bool({}), bool({3})" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "* `list` [[doc]](https://docs.python.org/3/library/stdtypes.html#list) turns its argument into a `python` list (if possible)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "list(\"networks\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "source": [ + "* **list comprehension** [[doc]](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions) allows the construction of new list from old ones\n", + "without explicit `for` loops (or `if` statements)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hideCode": false, + "hidePrompt": false + }, + "outputs": [], + "source": [ + "[(x, y) for x in range(4) for y in range(4) if x < y]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hideCode": false, + "hidePrompt": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Exercises\n", + "\n", + "1. For what values of $n$ is $K_n$ bipartite?\n", + "2. For what values of $m$ and $n$ is $K_{m,n}$ bipartite?\n", + "3. For what values of $n$ is $P_n$ bipartite?\n", + "4. For what values of $n$ is $C_n$ bipartite?\n", + "5. In this class we looked at a few graph generators in `networkx`. Explore the following: `barbell_graph`, `ladder_graph`, `lollipop_graph`, `star_graph` and `wheel_graph`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Finished here Wednesday
" + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "hide_code_all_hidden": false, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.1" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": true, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}