1107 lines
28 KiB
Plaintext
1107 lines
28 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"hideCode": false,
|
|
"hidePrompt": false,
|
|
"toc": true
|
|
},
|
|
"source": [
|
|
"<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
|
|
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#News:\" data-toc-modified-id=\"News:-1\"><span class=\"toc-item-num\">1 </span>News:</a></span><ul class=\"toc-item\"><li><span><a href=\"#Labs\" data-toc-modified-id=\"Labs-1.1\"><span class=\"toc-item-num\">1.1 </span>Labs</a></span></li><li><span><a href=\"#Website\" data-toc-modified-id=\"Website-1.2\"><span class=\"toc-item-num\">1.2 </span>Website</a></span></li></ul></li><li><span><a href=\"#networkx\" data-toc-modified-id=\"networkx-2\"><span class=\"toc-item-num\">2 </span><code>networkx</code></a></span><ul class=\"toc-item\"><li><span><a href=\"#Check-basic-properties:\" data-toc-modified-id=\"Check-basic-properties:-2.1\"><span class=\"toc-item-num\">2.1 </span>Check basic properties:</a></span></li><li><span><a href=\"#Adding-and-removing-nodes-and-edges\" data-toc-modified-id=\"Adding-and-removing-nodes-and-edges-2.2\"><span class=\"toc-item-num\">2.2 </span>Adding and removing nodes and edges</a></span></li></ul></li><li><span><a href=\"#Neighbours-and-degree\" data-toc-modified-id=\"Neighbours-and-degree-3\"><span class=\"toc-item-num\">3 </span>Neighbours and degree</a></span></li><li><span><a href=\"#Important-Graphs\" data-toc-modified-id=\"Important-Graphs-4\"><span class=\"toc-item-num\">4 </span>Important Graphs</a></span><ul class=\"toc-item\"><li><span><a href=\"#Complete-Graphs\" data-toc-modified-id=\"Complete-Graphs-4.1\"><span class=\"toc-item-num\">4.1 </span>Complete Graphs</a></span></li><li><span><a href=\"#Bipartite-Graphs\" data-toc-modified-id=\"Bipartite-Graphs-4.2\"><span class=\"toc-item-num\">4.2 </span>Bipartite Graphs</a></span></li><li><span><a href=\"#Complete-Bipartite-Graphs\" data-toc-modified-id=\"Complete-Bipartite-Graphs-4.3\"><span class=\"toc-item-num\">4.3 </span>Complete Bipartite Graphs</a></span></li><li><span><a href=\"#Path-Graphs\" data-toc-modified-id=\"Path-Graphs-4.4\"><span class=\"toc-item-num\">4.4 </span>Path Graphs</a></span></li><li><span><a href=\"#Cycle-Graphs\" data-toc-modified-id=\"Cycle-Graphs-4.5\"><span class=\"toc-item-num\">4.5 </span>Cycle Graphs</a></span></li><li><span><a href=\"#Petersen-Graph\" data-toc-modified-id=\"Petersen-Graph-4.6\"><span class=\"toc-item-num\">4.6 </span>Petersen Graph</a></span></li></ul></li><li><span><a href=\"#Code-Corner\" data-toc-modified-id=\"Code-Corner-5\"><span class=\"toc-item-num\">5 </span>Code Corner</a></span><ul class=\"toc-item\"><li><span><a href=\"#python\" data-toc-modified-id=\"python-5.1\"><span class=\"toc-item-num\">5.1 </span><code>python</code></a></span></li></ul></li><li><span><a href=\"#Exercises\" data-toc-modified-id=\"Exercises-6\"><span class=\"toc-item-num\">6 </span>Exercises</a></span></li></ul></div>"
|
|
]
|
|
},
|
|
{
|
|
"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",
|
|
"<div class=\"rc\"><font size=\"-1\"><em>This version of this notebook was written by Niall Madden, adapted from notebooks by Angela Carnevale.</em></div>"
|
|
]
|
|
},
|
|
{
|
|
"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": [
|
|
"<div class=\"alert alert-block alert-info\">Finished here Wednesday</div>"
|
|
]
|
|
}
|
|
],
|
|
"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
|
|
}
|