execute_notebooks :cache# Whether to execute notebooks at build time. Must be one of ("auto", "force", "cache", "off")
cache :"_build/.jupyter_cache/"# A path to the jupyter cache that will be used to store execution artifacs. Defaults to `_build/.jupyter_cache/`
exclude_patterns :["README.md","*.ipynb","parallelisierung_lecture.md","parallelisierung_exercise.md","performance_lecture.md","performance_exercise.md","streams_lecture.md"]# A list of patterns to *skip* in execution (e.g. a notebook that takes a really long time)
exclude_patterns :["README.md","*.ipynb","parallelisierung_lecture.md","parallelisierung_exercise.md","streams_lecture.md"]# A list of patterns to *skip* in execution (e.g. a notebook that takes a really long time)
execute_notebooks :cache# Whether to execute notebooks at build time. Must be one of ("auto", "force", "cache", "off")
cache :"_build/.jupyter_cache/"# A path to the jupyter cache that will be used to store execution artifacs. Defaults to `_build/.jupyter_cache/`
exclude_patterns :["README.md","*.ipynb","parallelisierung_lecture.md","parallelisierung_exercise.md","performance_lecture.md","performance_exercise.md","streams_lecture.md"]# A list of patterns to *skip* in execution (e.g. a notebook that takes a really long time)
exclude_patterns :["README.md","*.ipynb","parallelisierung_lecture.md","parallelisierung_exercise.md"]# A list of patterns to *skip* in execution (e.g. a notebook that takes a really long time)
Hier wurde eine **Exception** ausgelöst, die den aufgetretenen Fehler repräsentiert. Die Exception hat hier die Klasse `IndexError`, es handelt sich also um einen Indizierungs-Fehler.
```{code-cell}
:tags: ["raises-exception"]
```{code-cell} ipython3
:tags: [raises-exception]
def function_with_error():
print('Start')
print(1 / 0)
...
...
@@ -65,12 +69,13 @@ Weder `except` noch `finally` muss verwendet werden, allerdings mindestens eins
- Allerdings: die Befehle im `finally`-Block werden *in jedem Fall* ausgeführt, egal ob ein Fehler ausgelöst wurde oder nicht oder ob der Fehler behandelt wurde oder nicht.
```{code-cell}
```{code-cell} ipython3
a = [1, 2, 3]
try:
print(a[3])
print(a)
except IndexError as e:
print('Error occured: {}'.format(str(e)))
print('Error occured: {}'.format(str(e)))
```
### Propagation von Exceptions
...
...
@@ -81,7 +86,7 @@ Ungewöhnlich dabei ist, dass die Verschachtelung der `try`-`except`-Blöcke nic
#### Beispiel (etwas künstlich...)
```{code-cell}
```{code-cell} ipython3
def eval_string(s):
"""Zerlegt einen String der Form 'x op y', wobei
x und y Darstellungen von Integern sind und op +, -,
...
...
@@ -123,20 +128,21 @@ Die Fehler werden im Folgenden immer in `eval_string` ausgelöst, aber an unters
- Ungültige Eingabe: `eval_string` wird beendet, `eval_list` behandelt den Fehler.
- Division durch 0: `eval_string` und `eval_list` werden beendet, `sum_of_list` behandelt den Fehler.
```{code-cell}
```{code-cell} ipython3
print(sum_of_list(['1 / 0']))
```
- Eingabe ist kein String: der Fehler wird nicht behandelt, alle Funktionen werden beendet, die Notebook-Zelle wird beendet. Jupyter behandelt den Fehler implizit. Ein eigenständiges Programm würde hier abbrechen.
```{code-cell}
:tags: ["raises-exception"]
```{code-cell} ipython3
:tags: [raises-exception]
print(sum_of_list([12, 13, 14]))
print('Fertig.')
```
...
...
@@ -180,8 +186,9 @@ Eine Exception wird mit `raise` ausgelöst. Das Exception-Objekt muss eine Insta
Wie genau die Exception-Instanzen erzeugt werden, hängt von der konkreten Klasse ab. Meist nehmen sie allerdings ein einzelnes String-Argument als Fehlermeldung.
```{code-cell}
:tags: ["raises-exception"]
```{code-cell} ipython3
:tags: [raises-exception]
raise ValueError('Illegal input')
```
...
...
@@ -195,8 +202,9 @@ raise
ohne Argument verwenden. In diesem Fall wird die aktuelle Exception neu ausgelöst und propagiert weiter. Das ist nützlich, wenn man auf die Exception reagieren will, aber nicht letztenendes entscheiden kann, ob der Fehler ignoriert werden soll. In diesem Fall muss ggf. darüberliegender Code ebenfalls auf die Exception reagieren.
```{code-cell}
:tags: ["raises-exception"]
```{code-cell} ipython3
:tags: [raises-exception]
try:
raise ValueError('Something went wrong')
except:
...
...
@@ -214,20 +222,22 @@ Exceptions werden oft ausgelöst, wenn bestimmte Bedingungen nicht erfüllt sind
`assert` überprüft die `<Bedingung>`. Wird diese zu einem *falschen* Wert ausgewertet, wird eine `AssertionError`-Exception ausgelöst, optional mit der gegebenen Fehlermeldung.
```{code-cell}
```{code-cell} ipython3
def first_element(lst):
assert isinstance(lst, list), 'wrong type argument'
for kind in ['nearest', 'linear', 'quadratic', 'cubic', 5, 7]
...
...
@@ -224,7 +226,7 @@ erfüllen.
**Beispiel: Fitting eines Polynoms vom Grad $n = 6$**
```{code-cell}
```{code-cell} ipython3
V = np.vander(interp_x, 7)
P = np.poly1d(spl.solve(V.T @ V, V.T @ interp_y))
...
...
@@ -241,7 +243,7 @@ numpy.polyfit(x, y, n)
Das Resultat ist ein Koeffizienten-Array, aus dem man mit `poly1d` ein Polynom-Objekt erzeugen kann.
```{code-cell}
```{code-cell} ipython3
P = np.poly1d(np.polyfit(interp_x, interp_y, 6))
plot_with_points(P, 'Polynom-Fit')
...
...
@@ -258,12 +260,12 @@ scipy.interpolate.UnivariateSpline(x, y, s=None)
-`x, y`: wie gehabt die Datenpunkte, die bekannt sind
-`s`: Glättungsfaktor (*smoothing factor*); steuert, wieviele Punkte für die Splineinterpolation genutzt werden. Kleiner bedeutet mehr Punkte.
```{code-cell}
```{code-cell} ipython3
f = spi.UnivariateSpline(interp_x, interp_y)
plot_with_points(f, 'Spline-Fit')
```
```{code-cell}
```{code-cell} ipython3
f = spi.UnivariateSpline(interp_x, interp_y, s=0.2)
plot_with_points(f, 'Spline-Fit')
```
...
...
@@ -299,7 +301,7 @@ Allgemeiner funktionieren auch Daten in `d` Dimensionen, wenn `points` und `xi`
Für die `'linear'`- und `'cubic'`-Methoden kann nur auf die *konvexe Hülle* der gegebenen `points` interpoliert werden. An anderen Punkten von `xi` wird `NaN` zurückgegeben. Für den Umgang damit kann die Funktion `numpy.isnan` nützlich sein (s.u.).
```{code-cell}
```{code-cell} ipython3
def f(x, y):
return np.cos(4*np.pi*x) * np.sin(4*np.pi*y)
...
...
@@ -311,7 +313,7 @@ values = f(*points.T)
X, Y = np.ogrid[0:1:50j, 0:1:50j]
```
```{code-cell}
```{code-cell} ipython3
hv.Layout((
hv.Image((X.ravel(), Y.ravel(), f(X, Y).T)),
hv.Scatter(
...
...
@@ -323,7 +325,7 @@ hv.Layout((
))
```
```{code-cell}
```{code-cell} ipython3
# (n, 2)-Array mit den Koordinaten aller Punkte
xfull, yfull = np.broadcast_arrays(X, Y)
xi = np.stack((xfull.ravel(), yfull.ravel()), axis=1)
...
...
@@ -339,7 +341,7 @@ hv.Layout(gr).cols(2)
Umgang mit `NaN`, z.B. Fortsetzen als 0 auf Außenbereich:
```{code-cell}
```{code-cell} ipython3
p[np.isnan(p)] = 0
hv.Image((X.ravel(), Y.ravel(), p.T))
```
...
...
@@ -350,26 +352,26 @@ Arrays können auch durch sogenannte **Boolsche Masken** indiziert werden, d.h.
Das ist besonders nützlich in Verbindung mit Vergleichsoperatoren, deren Resultat Bool-Arrays sind (s.o.).
```{code-cell}
```{code-cell} ipython3
a = np.arange(25).reshape((5, 5))
a % 2 == 0
```
```{code-cell}
```{code-cell} ipython3
b = a[a % 2 == 0]
b
```
Masken können auch auf der linken Seite einer Zuweisung verwendet werden.
```{code-cell}
```{code-cell} ipython3
a[a % 2 == 0] = -1
a
```
Darüber hinaus können Masken auch nur entlang einer einzelnen Achse eingesetzt werden.
```{code-cell}
```{code-cell} ipython3
a = np.arange(25).reshape((5, 5))
mask = np.array([True, True, False, True, False])
...
...
@@ -387,8 +389,13 @@ array_object.any(axis=None)
Das `axis`-Argument funktioniert wie bei anderen Reduktionen (`sum`, `mean`, etc).
@@ -55,7 +57,7 @@ Die Rückgabe der Funktion enthält mehrere Attribute:
$x \cdot e^x - 1 = 0$
```{code-cell}
```{code-cell} ipython3
def f(x):
return x * np.exp(x) - 1
...
...
@@ -63,7 +65,7 @@ res = spopt.root(f, [1])
res
```
```{code-cell}
```{code-cell} ipython3
%output size=150
x = np.linspace(-0.5, 1.5, 100)
...
...
@@ -76,7 +78,7 @@ $\begin{cases} x^2 \cdot y = 2 \\ x \cdot y^2 = 1 \end{cases}$
Hier wollen wir auch die Jacobi-Matrix benutzen. Wir haben vor ein paar Vorlesungen `SymPy` kennengelernt, wodurch wir Ableitungen symbolisch ausrechnen können. Das nutzen wir nun. Insbesondere bei komplexeren Funktionen/Gleichungen wollen wir die Jacobi-Matrix nicht mehr selbst ausrechnen.
```{code-cell}
```{code-cell} ipython3
x, y = sy.symbols('x, y')
fsym = sy.Matrix([x**2 * y - 2, x * y**2 - 1])
dfsym = fsym.jacobian((x, y))
...
...
@@ -85,7 +87,7 @@ dfsym
Die symbolische Funktion und die Jacobi-Matrix sind so noch nicht für die numerischen Algorithmen auf effiziente Weite nutzbar. Wir müssen sie wieder mit lambdify zu numerisch auswertbaren Funktionen konvertieren. Der 2. Schritt zur Transformation der Argumente und Rückgabewerte ist nötig, damit sie zu den Anforderungen von `root` passen.