diff --git a/02-numpy/02-numpy.tex b/02-numpy/02-numpy.tex
new file mode 100644
index 0000000000000000000000000000000000000000..ef8dace02b7dfadf279e4878e64750fc9b4b8c00
--- /dev/null
+++ b/02-numpy/02-numpy.tex
@@ -0,0 +1,410 @@
+\documentclass{beamer}
+\usepackage[utf8]{inputenc}
+\usepackage[czech]{babel}
+\usepackage{palatino}
+\usepackage{verbatim}
+\usetheme{Warsaw}
+\title{Programování 2: Knihovna NumPy}
+\author[Martin Mareš]{Martin Mareš\\\texttt{mj@ucw.cz}}
+\institute{Katedra Aplikované Matematiky\\MFF UK Praha}
+\date{2020}
+\setbeamersize{text margin left=5mm}
+\setbeamersize{text margin right=5mm}
+\begin{document}
+\setbeamertemplate{navigation symbols}{}
+\setbeamertemplate{footline}{}
+\setbeamerfont{title page}{family=\rmfamily}
+\shorthandoff{"}
+
+\begin{frame}
+\titlepage
+\end{frame}
+
+\input ../slidemac.tex
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Jak si pořídit matici}
+
+\py{%
+import numpy as np\\
+a = np.array([[1, 2, 3], [4, 5, 6]])\\
+a  \cmt{(np.array je libovolně-rozměrné homogenní pole)}
+}{%
+array([[1, 2, 3],\\
+~~~~~~~[4, 5, 6]])
+}
+
+\py{%
+a.ddim  \cmt{(kolikarozměrné je naše pole)}
+}{%
+2
+}
+
+\py{%
+a.shape  \cmt{(tvar pole)}
+}{%
+(2, 3)
+}
+
+\py{%
+a.size  \cmt{(celkový počet prvků)}
+}{%
+(2, 3)
+}
+
+\py{%
+a.dtype  \cmt{(typ dat společný pro všechny prvky)}
+}{%
+dtype('int64')  \cmt{(můžeme zvolit při vytváření pole)}
+}
+
+\py{%
+a.itemsize  \cmt{(velikost jednoho prvku v~paměti)}
+}{%
+8
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Nuly a jedničky}
+
+\py{%
+np.zeros((2, 2))
+}{%
+array([[0., 0.],\\
+~~~~~~~[0., 0.]])
+}
+
+\py{%
+np.zeros((2, 2), dtype=np.int8)
+}{%
+array([[0, 0],\\
+~~~~~~~[0, 0]], dtype=int8)
+}
+
+\py{%
+np.ones((2, 2))
+}{%
+array([[1., 1.],\\
+~~~~~~~[1., 1.]])
+}
+
+\py{%
+a = np.array([[1, 2, 3], [4, 5, 6]])\\
+np.zeros\_like(a)
+}{%
+array([[0, 0, 0],\\
+~~~~~~~[0, 0, 0]])
+}
+
+\py{%
+np.identity(2)  \cmt{(nebo také {\tt np.eye})}
+}{%
+array([[1., 0.],\\
+~~~~~~~[0., 1.]])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Generátory polí}
+
+\py{%
+np.arange(10)
+}{%
+array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+}
+
+\py{%
+np.arange(1, 2, 0.1)
+}{%
+array([1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9])
+}
+
+\py{%
+np.linspace(1, 2, 10)
+}{%
+array([1.        , 1.11111111, 1.22222222, 1.33333333, 1.44444444,
+       1.55555556, 1.66666667, 1.77777778, 1.88888889, 2.        ])
+}
+
+\py{%
+np.arange(6).reshape((2, 3))
+}{%
+array([[0, 1, 2],\\
+~~~~~~~[3, 4, 5]])
+}
+
+\py{%
+np.random.random((2, 2))  \cmt{(mezi 0 a~1)}
+}{%
+array([[0.3530976 , 0.32314115],\\
+~~~~~~~[0.04913276, 0.86769289]])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Aritmetika s~poli}
+
+\py{%
+a = np.arange(4).reshape((2,2))\\
+a
+}{%
+array([[0, 1],\\
+~~~~~~~[2, 3]])
+}
+
+\py{%
+a + a  \cmt{(sčítání po složkách)}
+}{%
+array([[0, 2],\\
+~~~~~~~[4, 6]])
+}
+
+\py{%
+a * a  \cmt{(násobení po složkách)}
+}{%
+array([[0, 1],\\
+~~~~~~~[4, 9]])
+}
+
+\py{%
+a @ a  \cmt{(maticové násobení)}
+}{%
+array([[ 2,  3],\\
+~~~~~~~[ 6, 11]])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Rozšiřování argumentů (broadcasting)}
+
+\py{%
+a = np.ones((2, 3))\\
+a*3
+}{%
+array([[3., 3., 3.],
+       [3., 3., 3.]])
+}
+
+\py{%
+a * np.array([1, 2, 3])
+}{%
+array([[1., 2., 3.],\\
+~~~~~~~[1., 2., 3.]])
+}
+
+\py{%
+a * np.array([[6], [7]])
+}{%
+array([[6., 6., 6.],\\
+~~~~~~~[7., 7., 7.]])
+}
+
+\smallskip
+
+Pravidla rozšiřování -- pro každý index {\bf od konce}:
+
+\begin{itemize}
+\item Pokud jsou rozměry stejné, nedělej nic.
+\item Pokud je jeden roven~1, rozšiř ho podle druhého.
+\item Pokud jsou jinak různé, vyhlaš chybu.
+\item Pokud už jednomu poli došly indexy, domysli si rozměr~1.
+\end{itemize}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Další aritmetika}
+
+\py{%
+a = (2**np.arange(12)\%11).reshape((3,4))\\
+a
+}{%
+array([[~1,~~2,~~4,~~8],\\
+~~~~~~~[~5,~10,~~9,~~7],\\
+~~~~~~~[~3,~~6,~~1,~~2]])
+}
+
+\py{%
+a.max()
+}{%
+10
+}
+
+\py{%
+a.max(axis=0)  \cmt{(maximum po řádcích)}
+}{%
+array([ 5, 10,  9,  8])
+}
+
+\py{%
+a.max(axis=1)  \cmt{(maximum po sloupcích)}
+}{%
+array([ 8, 10,  6])
+}
+
+\py{%
+a.sum(axis=0)  \cmt{(součet po řádcích)}
+}{%
+array([ 9, 18, 14, 17])
+}
+
+U~vícerozměrných polí může být {\bf axis} i tuple více indexů.
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Indexování a řezy}
+
+\py{%
+a = np.arange(12).reshape((2,2,3))
+}{%
+array([[[~0,~~1,~~2],\\
+~~~~~~~~[~3,~~4,~~5]],\\
+~~~~~~~[[~6,~~7,~~8],\\
+~~~~~~~~[~9,~10,~11]]])
+}
+
+\py{%
+a[0,1,2]
+}{%
+5
+}
+
+\py{%
+a[0,1]
+}{%
+array([3, 4, 5])
+}
+
+\py{%
+a[0,1,1:3]
+}{%
+array([4, 5])
+}
+
+\py{%
+a[:,:,0]  \cmt{(zkratka: {\tt a[..., 0]})}
+}{%
+array([[0, 3],\\
+~~~~~~~[6, 9]])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Transpozice a spol.}
+
+\py{%
+a = np.arange(6).reshape((2, 3))\\
+a
+}{%
+array([[0, 1, 2],\\
+~~~~~~~[3, 4, 5]])
+}
+
+\py{%
+a.T  \cmt{(transpozice, obecněji: {\tt a.swapaxes(0, 1)})}
+}{%
+array([[0,~3],\\
+~~~~~~~[1,~4],\\
+~~~~~~~[2,~5]])
+}
+
+\py{%
+a[:,np.newaxis,:]
+}{%
+array([[[0,~1,~2]],\\
+~~~~~~~[[3,~4,~5]]])
+}
+
+\py{%
+np.arange(1,4)[:,np.newaxis] * np.arange(1,5)
+}{%
+array([[~1,~~2,~~3,~~4],\\
+~~~~~~~[~2,~~4,~~6,~~8],\\
+~~~~~~~[~3,~~6,~~9,~12]])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Vybírání prvků}
+
+\py{%
+b = 2**np.arange(10) % 13\\
+b
+}{%
+array([ 1,  2,  4,  8,  3,  6, 12, 11,  9,  5])
+}
+
+\py{%
+b[np.array([2, 3, 4])] \hskip-5mm\cmt{(indexování číselným vektorem)}
+}{%
+array([4, 8, 3])
+}
+
+\py{%
+b < 7
+}{%
+array([~True,~~True,~~True,~False,~~True,~~True,\\
+~~~~~~~False,~False,~False,~True])
+}
+
+\py{%
+b[b < 7]  \cmt{(indexování booleovským vektorem)}
+}{%
+array([1, 2, 4, 3, 6, 5])
+}
+
+\py{%
+b[b < 7] = 0\\
+b
+}{%
+array([ 0,  0,  0,  8,  0,  0, 12, 11,  9,  0])
+}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\begin{frame}{Slepování polí}
+
+\py{%
+a = np.ones((2, 2))\\
+b = np.zeros((2, 2))\\
+np.vstack((a, b))
+}{%
+array([[1.,~1.],\\
+~~~~~~~[1.,~1.],\\
+~~~~~~~[0.,~0.],\\
+~~~~~~~[0.,~0.]])
+}
+
+\py{%
+np.hstack((a, b))
+}{%
+array([[1., 1., 0., 0.],\\
+~~~~~~~[1., 1., 0., 0.]])
+}
+
+Obecněji: {\tt np.concatenate}, {\tt np.stack}
+
+\end{frame}
+
+% ----------------------------------------------------------------------
+
+\end{document}
diff --git a/02-numpy/Makefile b/02-numpy/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..28c31cc7f45b004355278abe87ffb6615bb533f5
--- /dev/null
+++ b/02-numpy/Makefile
@@ -0,0 +1,3 @@
+SLIDES=02-numpy.pdf
+
+include ../Makerules
diff --git a/02-numpy/notes b/02-numpy/notes
new file mode 100644
index 0000000000000000000000000000000000000000..768f3754cb7e9afc94e49ba8a4af4e14bfb7cea2
--- /dev/null
+++ b/02-numpy/notes
@@ -0,0 +1,58 @@
+https://numpy.org/devdocs/reference/
+
+np.array([], dtype=...)
+np.zeros((3, 4))
+np.ones((3, 4), dtype=...)
+zeros_like
+ones_like
+reshape
+arange
+linspace
++ * @
+a.sum(), min, max
+a.sum(axis=0)
+a.shape  [pozor, není to funkce]
+slices  [pozor, nekopírují]
+a.copy()
+stretching
+
+
+
+
+matplotlib.pyplot.annotate(s, xy, *args, **kwargs)
+axis(\*args, \*\*kwargs)
+bar
+clf()
+figlegend
+
+fig = figure(figsize=...)
+grid
+hist ?
+savefig
+show
+
+subplot
+title
+xlabel
+ylabel
+xlim
+ylim
+x/yscale
+suptitle
+
+text
+
+tick_params
+
+xkcd
+
+
+
+random.seed
+randrange
+random
+uniform
+choice
+choices(list, k=10)
+shuffle(list)
+sample(list, k=10)
diff --git a/Makerules b/Makerules
new file mode 100644
index 0000000000000000000000000000000000000000..67126a904a8af05606898d59b78da1cf90af2403
--- /dev/null
+++ b/Makerules
@@ -0,0 +1,14 @@
+export SHELL=/bin/bash
+
+all: $(SLIDES)
+
+%.pdf: %.tex $(wildcard *.py)
+	pdflatex $<
+
+clean::
+	rm -f *.{aux,log,nav,out,snm,toc,vrb}
+	rm -f *.pdf
+	rm -rf __pycache__
+
+upload::
+	rs $(SLIDES) jw:www/static/vyuka/1920/p2m/
diff --git a/slidemac.tex b/slidemac.tex
new file mode 100644
index 0000000000000000000000000000000000000000..4b2f7b83ae710faebdc6fef85a6a63f0212b05c8
--- /dev/null
+++ b/slidemac.tex
@@ -0,0 +1,19 @@
+\def\pyprompt{\color{black}>>> \color{blue}}
+\def\pydots{\color{black}... \color{blue}}
+\def\>{\hphantom{xxxx}}
+
+\def\=#1{{\color{teal}#1}\endgraf\smallskip}
+
+\def\py#1#2{%
+	\def\tmp{#1}\ifx\tmp\empty\else
+		{\tt\def\\{\hfil\break\pyprompt}\def\.{\hfil\break\pydots}\pyprompt #1}\\%
+	\fi
+	\def\tmp{#2}\ifx\tmp\empty\else
+		{\tt\color{red}#2}\\%
+	\fi
+	\medskip
+}
+
+\def\cmt#1{\quad\hbox{\color{black}\rm #1}}
+
+\def\bs{\char92\relax}