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.
Definiere die folgenden Vektoren und Matrizen
# 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]])
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:
Kontrolliere, dass du das richtige Resultat bekommst. Bei Arrays wird nicht alles als Vektoroperation ausgeführt.
# 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)
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
.
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
Um besondere Matrizen einfach eingeben zu können bestehen extra Funktionen. Verwende die
Funktionen eye, zeros und ones um folgenden
Matrizen einzugeben:
A = zeros((2,3)) B = ones((3,4)) C = eye(4) # Um Matrizen zu erzeugen, verwendest du z.B. # matrix(eye(4))
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.
Gib die Matrizen D, E und F ein und bestimme ihre Determinante, ihre Dimensionen, ihre Norm,
und ihren Rang.
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
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.
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.
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.
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.
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.
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!
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.
from pylab import * def zeit(s, a = 9.81): return sqrt(2/a*s) # [...] t_theorie = zeit(h_theorie) # [...]
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
Ergänze beschleunigt.py durch je ein analoge Funktion, welche die Beschleunigung bzw. die Strecke berechnet.
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
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
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.
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()
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.
Definiere je eine Funktion, die das Skala- bzw. das Vektorprodukt von zwei 3-Komponenten Vektoren berechnet. (Ohne die pylab-Funktionen zu verwenden.)