Skip to content

Commit 29f94a9

Browse files
committed
part 3: signals
1 parent 095e10f commit 29f94a9

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

notebooks/03_signals.ipynb

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# 3 Graph signals\n",
8+
"\n",
9+
"A graph signal is a function $\\mathcal{V} \\rightarrow \\mathbb{R}$ that associates a value to each node $v \\in \\mathcal{V}$ of a graph. The signal values can be represented as a vector $f \\in \\mathbb{R}^N$ where $N = |\\mathcal{V}|$ is the number of nodes in the graph."
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": null,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"import numpy as np\n",
19+
"from pygsp import graphs"
20+
]
21+
},
22+
{
23+
"cell_type": "markdown",
24+
"metadata": {},
25+
"source": [
26+
"Let's generate a graph and a random signal."
27+
]
28+
},
29+
{
30+
"cell_type": "code",
31+
"execution_count": null,
32+
"metadata": {},
33+
"outputs": [],
34+
"source": [
35+
"graph = graphs.Sensor(N=100)\n",
36+
"signal = np.random.normal(size=graph.N)"
37+
]
38+
},
39+
{
40+
"cell_type": "markdown",
41+
"metadata": {},
42+
"source": [
43+
"We can now plot the signal on the graph to visualize it and see that it's indeed random."
44+
]
45+
},
46+
{
47+
"cell_type": "code",
48+
"execution_count": null,
49+
"metadata": {},
50+
"outputs": [],
51+
"source": [
52+
"graph.plot_signal(signal)"
53+
]
54+
},
55+
{
56+
"cell_type": "markdown",
57+
"metadata": {},
58+
"source": [
59+
"## 3.1 Gradient and divergence\n",
60+
"\n",
61+
"The gradient $\\nabla_\\mathcal{G} \\ f$ of the signal $f$ on the graph $\\mathcal{G}$ is a signal on the edges defined as\n",
62+
"\n",
63+
"$$(\\nabla_\\mathcal{G})_{(i,j)} \\ f = \\sqrt{W_{ij}} (f_i - f_j)$$"
64+
]
65+
},
66+
{
67+
"cell_type": "code",
68+
"execution_count": null,
69+
"metadata": {},
70+
"outputs": [],
71+
"source": [
72+
"graph.compute_differential_operator()\n",
73+
"gradient = graph.D @ signal\n",
74+
"assert gradient.size == graph.Ne"
75+
]
76+
},
77+
{
78+
"cell_type": "markdown",
79+
"metadata": {},
80+
"source": [
81+
"Similarly, we can compute the divergence of an edge signal, which is again a signal on the nodes.\n",
82+
"\n",
83+
"$$(\\operatorname{div}_\\mathcal{G} x)_i = \\sum_{j \\sim i} \\sqrt{W_{ij}} x_{(i,j)}$$"
84+
]
85+
},
86+
{
87+
"cell_type": "code",
88+
"execution_count": null,
89+
"metadata": {},
90+
"outputs": [],
91+
"source": [
92+
"divergence = graph.D.T @ gradient\n",
93+
"assert divergence.size == graph.N"
94+
]
95+
},
96+
{
97+
"cell_type": "code",
98+
"execution_count": null,
99+
"metadata": {},
100+
"outputs": [],
101+
"source": [
102+
"graph.plot_signal(divergence)"
103+
]
104+
},
105+
{
106+
"cell_type": "markdown",
107+
"metadata": {},
108+
"source": [
109+
"The Laplacian operator is indeed the divergence of the gradient."
110+
]
111+
},
112+
{
113+
"cell_type": "code",
114+
"execution_count": null,
115+
"metadata": {},
116+
"outputs": [],
117+
"source": [
118+
"np.testing.assert_allclose(graph.L @ signal, divergence)"
119+
]
120+
},
121+
{
122+
"cell_type": "markdown",
123+
"metadata": {},
124+
"source": [
125+
"## 3.2 Smoothness"
126+
]
127+
},
128+
{
129+
"cell_type": "markdown",
130+
"metadata": {},
131+
"source": [
132+
"The smoothness of a signal can be computed by the quadratic form\n",
133+
"\n",
134+
"$$ f^\\intercal L f = \\sum_{i \\sim j} W_{ij} (f_i - f_j)^2 $$"
135+
]
136+
},
137+
{
138+
"cell_type": "code",
139+
"execution_count": null,
140+
"metadata": {},
141+
"outputs": [],
142+
"source": [
143+
"signal.T @ graph.L @ signal"
144+
]
145+
},
146+
{
147+
"cell_type": "markdown",
148+
"metadata": {},
149+
"source": [
150+
"## 3.3 Exercise\n",
151+
"\n",
152+
"What is the smoothest graph signal, i.e. the signal $f$ for which $f^\\intercal L f = 0$? Verify computationally."
153+
]
154+
},
155+
{
156+
"cell_type": "code",
157+
"execution_count": null,
158+
"metadata": {},
159+
"outputs": [],
160+
"source": [
161+
"# Your code here."
162+
]
163+
},
164+
{
165+
"cell_type": "markdown",
166+
"metadata": {},
167+
"source": [
168+
"What if $L$ is the normalized Laplacian? Verify computationally."
169+
]
170+
},
171+
{
172+
"cell_type": "code",
173+
"execution_count": null,
174+
"metadata": {},
175+
"outputs": [],
176+
"source": [
177+
"graph.compute_laplacian('normalized')\n",
178+
"\n",
179+
"# Your code here."
180+
]
181+
}
182+
],
183+
"metadata": {
184+
"kernelspec": {
185+
"display_name": "Python 3",
186+
"language": "python",
187+
"name": "python3"
188+
},
189+
"language_info": {
190+
"codemirror_mode": {
191+
"name": "ipython",
192+
"version": 3
193+
},
194+
"file_extension": ".py",
195+
"mimetype": "text/x-python",
196+
"name": "python",
197+
"nbconvert_exporter": "python",
198+
"pygments_lexer": "ipython3",
199+
"version": "3.7.0"
200+
}
201+
},
202+
"nbformat": 4,
203+
"nbformat_minor": 2
204+
}

0 commit comments

Comments
 (0)