Matrizen-Rechnungen und Funktionen

Block 5

Vektoren & Matrizen

Am Ende des letzten Blockes mussten ein Arrays transponieren. Damit hast du bereits deine erste Matrizen-Operation verwendet. Pylab bietet Funktionen für alle wichtigen Matrizen-Operation, so dass du damit auch Vektor- und Matrizen-Rechnung betreiben kannst. Du kannst dabei problemlos mit Arrays arbeiten. Oft ist es aber einfacher, echte (2D) Matrizen-Objekte zu verwenden. Matrizen erzeugst du analog zu Arrays mit dem Befehl matrix(). Löse die folgenden Aufgaben mit Arrays oder Matrizen.

Aufgabe 1

Definiere die folgenden Vektoren und Matrizen

Lösung anzeigen

# Arrays a=array([1, 5]) b=array([2, 9, -1]) A=array([[1, 2],[7, 4]]) B=array([[1, -2, 5],[-2, 7, 3]]) # Matrizen a=matrix([1, 5]) b=matrix([2, 9, -1]) A=matrix([[1, 2],[7, 4]]) B=matrix([[1, -2, 5],[-2, 7, 3]])

Aufgabe 2

Definiere zusätzlich zu den bestehenden Variablen noch

c = array([-2, 3, 5])

Verwende dann die Operatoren *, ** und .T (transponieren) sowie die Funktionen np.cross und np.dot um folgende Matrix-Operationen auszuführen:

  1. aB
  2. BTaT
  3. bBT
  4. BBT
  5. BTB
  6. A2
  7. Skalarprodukt von c und b (hier gibt es zwei Lösungen)
  8. Vektorprodukt von b und c

Kontrolliere, dass du das richtige Resultat bekommst. Bei Arrays wird nicht alles als Vektoroperation ausgeführt.

Lösung anzeigen

# Arrays dot(a,B) dot(B.T,a.T) dot(b,B.T) dot(B,B.T) dot(B.T,B) dot(A,A) dot(c,b) # oder: sum(c*b) cross(b,c) # Matrix a*B B.T*a.T b*B.T B*B.T B.T*B A*A c*b.T cross(b,c)

Aufgabe 3

Aus der Linearen Algebra solltest du wissen, wie man mit Matrizen ein Gleichungssystem lösen kann. Stelle das Gleichungssystem

als Matrizen-Gleichung der Form Ax = b dar und bestimme x.

Tipp: Die zu A inverse Matrix bekommst du mit linalg.inv(A) bzw. A.I.

Lösung anzeigen

A = array([[-2,1],[0.5,2]]) b = array([[-3],[5]]) dot(linalg.inv(A),b) A = matrix([[-2,1],[0.5,2]]) b = matrix([[-3],[5]]) A.I*b

Aufgabe 4

Um besondere Matrizen einfach eingeben zu können bestehen extra Funktionen. Verwende die Funktionen eye, zeros und ones um folgenden Matrizen einzugeben:

Lösung anzeigen

A = zeros((2,3)) B = ones((3,4)) C = eye(4) # Um Matrizen zu erzeugen, verwendest du z.B. # matrix(eye(4))

Eigenschaften von Matrizen

Wie du aus der LinAlg wissen solltest, sind diverse Eigenschaften von Matrizen interessant. Für die folgende Aufgabe brauchst du die Funktionen size, shape, det, ndim, linalg.matrix_rank und norm. Schau dir die jeweilige Hilfe an.

Aufgabe 5

Gib die Matrizen D, E und F ein und bestimme ihre Determinante, ihre Dimensionen, ihre Norm, und ihren Rang.

Lösung anzeigen

D = eye(2) E = array([[0.1,-1],[100,0.1]]) F = array([[1,0,-5],[-3,7,-2],[4,-9,6]]) # Determinanten det(D) det(E) det(F) # Dimensionen ndim(E) size(E,0) size(E,1) shape(E) # oder E.shape # Norm norm(D) norm(E) norm(F) # Rang (mathematisch korrekt) linalg.matrix_rank(D) linalg.matrix_rank(E) linalg.matrix_rank(F) # Die gleichen Befehle funktionieren auch für Matrizen

Funktionen definieren

Wir wenden uns nun einem ganz neuen Thema zu. Bisher haben wir alle Befehle die wir ausführen wollten einfach untereinander geschrieben. Wenn wir ähnlichen Code mehrmals verwenden wollten, so haben wir ihn einfach kopiert. Die Lösung zur letzten Aufgabe hat deshalb viele sehr ähnliche Zeilen. Das ist nicht besonders elegant oder effizient. Eine bessere Lösung wäre, den mehrmals verwendeten Code in einen wiederverwendbaren Baustein zu verpacken. Funktionen sind genau solche Bausteine. Wir definieren also eine eigene Funktion eigenschaften.

def eigenschaften(M): print("shape:", shape(M)) print("det: ", det(M)) print("norm: ", norm(M)) print("rank: ", linalg.matrix_rank(M))

Anschliessend können wir unsere Funktion verwenden, wie jede andere Funktion in Python. Damit wird die Lösung um einiges einfacher:

D = eye(2) E = array([[0.1,-1],[100,0.1]]) F = array([[1,0,-5],[-3,7,-2],[4,-9,6]]) eigenschaften(D) eigenschaften(E) eigenschaften(F)

Betrachten wir nun also die Definition unserer Funktion etwas detaillierter. Das Keyword def markiert den Beginn einer Funktionsdefinition. Danach folgt der Funktionsname, den wir später auch für den Aufruf verwenden. In Klammern folgt dann eine Komma getrennte Liste mit den Argumenten der Funktion (wir haben hier nur 1 Argument). Schliesslich endet diese Zeile mit einem :. Wird die Funktion aufgerufen, so werden die Befehle im Funktionsblock ausgeführt. Der Funktionsblock enthält alle eingerückten Zeilen nach dem Doppelpunkt. Im Gegensatz zu vielen anderen Programmiersprachen ist das Einrücken bei Python nicht freiwillig. Python schaut auf die Leerzeichen am Anfang einer Zeile um zu bestimmen zu welchem Code-Block sie gehört. In unserem Fall enthält der Block also 4 Zeilen.

Hinweis: Beachte, dass der Name des Arguments nur innerhalb der Funktion relevant ist. Wir rufen eigenschaften(D) auf. In der Funktion selbst, ist das Argument jedes Aufrufs dann aber M. M enthält im Beispiel also einmal die Werte von D, einmal jene von E und einmal von F.

Aufgabe 6

Definiere eine Funktion, die zwei Vektoren als Argumente nimmt und sowohl das Skalar- wie auch das Vektorprodukt ausgibt. Teste deine Funktion danach mit verschiedenen Vektoren.

Lösung anzeigen

from pylab import * def produkte(v1, v2): print("Skalar:", dot(v1,v2)) print("Vektor:", cross(v1,v2)) a = array([1,0,0]) b = array([0,1,0]) c = array([1,1,1]) produkte(a,b) produkte(c,b) produkte(c,a)

Unsere ersten beiden Funktionen geben ihre Resultate auf der Konsole aus. Wollen wir mit dem Resultat weiterarbeiten, so ist das nicht besonders praktisch.

Eine Funktion kann deshalb auch einen oder mehrere Werte zurückgeben. Dafür verwendest du das Keyword return. Als Beispiel definieren wir eine Funktion, welche die Asymmetrie (Differenz durch Summe) von zwei Zahlen berechnet.

def asymmetrie(a, b): return (1.*a-b)/(a+b) asym1 = asymmetrie(3,5) asym2 = asymmetrie(50, 30) print(asym1, asym2)

Allfällige Zeilen nach der Return-Zeile werden nie erreicht und deshalb ignoriert.

Aufgabe 7

Schreibe eine Funktion mit einem Argument a, welche die Länge der Diagonalen in einem Quadrat mit Seitenlänge a berechnet. Verwende diese Funktion dann um die Fläche des roten Quadrats zu berechnen.
Zwei Quadrate, bei denen die Seite des grossen Quadrats der Diagonale des kleinen entspricht.

Lösung anzeigen

from pylab import * def diagonale(a): return sqrt(2)*a print("Fläche:", diagonale(5)**2)

Hinweis: Es ist wichtig, dass dir der Unterschied zwischen print und return klar ist. Falls du dir da noch nicht sicher bist, diskutiere den Unterschied mit deinem Nachbar oder uns.

Tricks für Funktionen

Wenn eine Funktion mehrerer Werte zurückgeben sollte, kannst du diese nach return mit Komma getrennt auflisten.

def sumdiff(a, b): return a+b, a-b retPair = sumdiff(3,5) retSum, retDiff = sumdiff(3,5) print("retPair", retPair) print("retSum ", retSum) print("retDiff", retDiff)

Ausserdem kannst du für jedes Argument einer Funktion auch einen Standardwert festlegen. Dieser wird verwendet, wenn beim Aufruf kein Wert übergeben wird.

def sumdiff(a, b = 0): return a+b, a-b print(sumdiff(3))

Von den Grafik-Funktionen kennst du die Möglichkeit, beim Funktionsaufruf bestimmte Argumente mit Namen zu übergeben. Diese Argumente heissen Keyword-Arguments. Das klappt natürlich nur, wenn für die ausgelassen Argumente einen Standardwert definiert ist.

def manyargs(a, b=1, c=2, d=3): return a*b-c*d print(manyargs(1)) # -5 print(manyargs(2,d=1)) # 0 print(manyargs(d=1)) # Fehler!

Aufgabe 8

Wir kehren wieder zu unserem Fall-Experiment zurück. Definiere eine python-Funktion, welche t = sqrt(2/a*s) berechnet. Verwende diese Funktion dann um die Theorie-Werte zu berechnen. Setze den Standardwert für a auf 9.81.

Lösung anzeigen

from pylab import * def zeit(s, a = 9.81): return sqrt(2/a*s) # [...] t_theorie = zeit(h_theorie) # [...]

Programme und Module

Oft wirst du Funktionen definieren, die du auch in anderen Programmen verwenden kannst. Dazu kannst du Funktionen aus jeder python-Datei importieren. Oft macht es aber Sinn, wiederverwendbare Funktionen in eine separate Datei zu speichern. Verschiebe deshalb deine Funktion aus der letzten Aufgabe in eine neue Datei beschleunigt.py. In deinem Skript zum Fall-Experiment, importierst du dann die zeit-Funktion:

from beschleunigt import zeit

Aufgabe 9

Ergänze beschleunigt.py durch je ein analoge Funktion, welche die Beschleunigung bzw. die Strecke berechnet.

Lösung anzeigen

from pylab import sqrt _g = 9.81 def zeit(s, a = _g): return sqrt(2./a*s) def weg(t, a = _g): return 1/2.*a*t**2 def beschleunigung(s, t): return 2*s/t**2

pydoc

Du hast nun dein erstes eigenes Modul erstellt. Wenn du dich an die Empfehlungen gehalten hast, so ist es auch dokumentiert. Falls nicht, ist jetzt der Moment das nachzuholen. Dokumentiere die einzelnen Funktionen, aber auch ein globaler Doc-String zur Idee des Moduls ist oft hilfreich.

Dokumentation ist ein wichtiger Teil jedes Programms. Spätestens wenn du dein Modul in zwei Tagen wieder benutzen möchtest, bist du froh darum. Python bietet dir viele praktische Möglichkeiten um auf die Dokumentation zuzugreifen. So kannst du Spyder so einstellen, dass dir im 'Object inspector'-Fenster jeweils der Doc-String zum aktuellen Objekt angezeigt wird. (unter Tools / Preferences / Object inspector / Automatic connections)

import beschleunigt as bsl bsl.zeit(

Auch die Hilfe kennt nun deine Funktionen.

help(bsl.zeit) # oder bsl.zeit?

Du kannst die Dokumentation deines Moduls auch als eine Art man-Page darstellen lassen. Navigiere eine (Unix-)Shell in das Verzeichnis mit beschleunigt.py. Führe dann pydoc3 beschleunigt aus. Das klappt auch mit allen anderen Modulen: pydoc3 pylab

Ausführliche Doc-Strings

Wie du bei pylab siehst, kann deine Dokumentation sehr ausführlich werden. Die numpy Doc-String Convention enthält eine gute Übersicht und viele nützliche Tipps. Eine lohnenswerte Ergänzung zu minimalen Doc-Strings sind Informationen zu den Parametern und Rückgabewerten von Funktionen.

def zeit(s, a): """ berechnet Zeit aus Weg und Beschleunigung Parameters ---------- s : Float or Array Zurückzulegende Strecke a : Float Wirkende Beschleunigung Returns ------- t : Zeit Für s benötigte Zeit """ return sqrt(2./a*s)

Für so einfach Funktionen ist dieser Kommentar natürlich etwas übertrieben. Bald wirst du aber auch komplizierte Funktionen definieren und dann bist du froh um sauber strukturierte Doc-Strings.

Aufgaben zur Vertiefung

Lagerkräfte

Berechne für das unten stehende Fachwerk die Lagerkräfte (FAx, FAy, FBx). Die Bewegungsgleichungen für das Fachwerk findest du unten. Drücke dieses Gleichungssystem als Matrizengleichung aus und löse diese.

mit
F1 = 2 [kN], F2 = 1 [kN]
= 45° und = 30°
a = 1 [m], b = a/tan()

Mittelwert mit Fehler

Definiere eine Funktion, die als Argument ein Array oder eine Liste übernimmt. Die Funktion soll aus den enthaltenen Werten den Mittelwert und den dazugehörigen Fehler berechnet und beide Zahlen zurück geben. Der Fehler auf dem Mittelwert ist gleich der Standard-Abweichung (std) geteilt durch die Wurzel der Anzahl Werte.

Skalar- und Vektorprodukt

Definiere je eine Funktion, die das Skala- bzw. das Vektorprodukt von zwei 3-Komponenten Vektoren berechnet. (Ohne die pylab-Funktionen zu verwenden.)