diff --git a/programming/code/logicalIndexingBenchmark.m b/programming/code/logicalIndexingBenchmark.m index 4a95184..80c4a87 100644 --- a/programming/code/logicalIndexingBenchmark.m +++ b/programming/code/logicalIndexingBenchmark.m @@ -1,7 +1,7 @@ -% create a vector with a random numbers +% create a vector with random numbers x = rand(1000000, 1); -fprintf('time needed to manually filter elements smaller than 0.5 in a vector of length %i\n', length(x)) +fprintf('Time needed to manually filter out elements smaller than 0.5 in a vector of length %i\n', length(x)) tic results = []; @@ -14,7 +14,7 @@ for i = 1:length(x) end toc -fprintf('\ntime needed to do the same with logical indexing\n') +fprintf('\nTime needed to do the same with logical indexing\n') tic results = x(x < 0.5); diff --git a/programming/code/logicalIndexingBenchmark.out b/programming/code/logicalIndexingBenchmark.out index 3161e95..f133b26 100644 --- a/programming/code/logicalIndexingBenchmark.out +++ b/programming/code/logicalIndexingBenchmark.out @@ -1,6 +1,6 @@ >> logicalIndexingBenchmark -time needed to manually filter elements smaller than 0.5 in a vector of length 100000 +Time needed to manually filter elements smaller than 0.5 in a vector of length 100000 Elapsed time is 0.008562 seconds. -time needed to do the same with logical indexing +Time needed to do the same with logical indexing Elapsed time is 0.001543 seconds. \ No newline at end of file diff --git a/programming/lectures/programming.tex b/programming/lectures/programming.tex index 5001a3f..6498e71 100644 --- a/programming/lectures/programming.tex +++ b/programming/lectures/programming.tex @@ -6,7 +6,7 @@ \subsection{Variablen} -aEine Variable ist ein Zeiger auf eine Stelle im Speicher. Dieser +Eine Variable ist ein Zeiger auf eine Stelle im Speicher. Dieser Zeiger hat einen Namen, den Variablennamen, und einen Datentyp (Abbildung \ref{variablefig}). Im Speicher wird der Wert der Variablen bin\"ar gespeichert. Wird auf den Wert der Variable zugegriffen, wird @@ -758,6 +758,23 @@ nun die Werte an den Stellen zur\"uck, an denen der logische Vektor von (\code{x}) an den Stellen, an denen \code{x < 5} wahr ist. \end{exercise} +Logisches Indizieren wurde oben so benutzt, dass die Auswahl auf dem +Inhalt desselben Vektors beruhte. Ein sehr h\"auiger Fall ist +jedoch, dass man die Auswahl aus einem Vektor auf den Inhalt eines +zweiten Vektors basiert. Ein Beispiel ist, dass man \"uber einen +gewissen Zeitraum Daten aufnimmt und aus diesen die Daten eines +bestimmten Zeitraums ausw\"ahlen m\"ochte (Abbildung +\ref{logicalindexingfig}). + + +\begin{figure}[h] + \includegraphics[width= 0.9\columnwidth]{logicalIndexingTime} + \caption{\texbf{Beispiel f\"ur ``indirektes'' logisches Indizieren.} + Der rot markierte Abschnitt aus den Daten wurde ``indirekt'' + anhand logischen Indizierens auf dem Zeitvektor + ausgew\"ahlt.}\label{logicalindexingfig} +\end{figure} + \begin{exercise}{logicalIndexingTime.m}{} Angenommen es werden \"uber einen bestimmten Zeitraum Messwerte genommen. Bei solchen Messungen er\"alt man einen Vektor, der die @@ -773,9 +790,6 @@ nun die Werte an den Stellen zur\"uck, an denen der logische Vektor \item Benutze das logische Indizieren um die Messwerte auszuw\"ahlen, die dem zeitlichen Abschnitt 5-6\,s entsprechen. \end{itemize} - \begin{figure} - \includegraphics[width=0.6\textwidth]{logicalIndexing_time.png} - \end{figure} \end{exercise} @@ -898,8 +912,8 @@ end \begin{exercise}{neverendingWhile.m}{} Implementiere eine \textbf{while}-Schleife, die unendlich - l\"auft. Tipp: der Boolesche Ausdruck hinter dem \textbf{while} muss - immer zu wahr ausgewertet werden. + l\"auft. Tipp: wenn der Boolesche Ausdruck hinter dem \textbf{while} + zu wahr ausgewertet wird, wird die Schleife weiter ausgef\"uhrt. \end{exercise} @@ -988,11 +1002,11 @@ auftreten k\"onnen, die einer unterschiedlichen Behandlung bed\"urfen. mynumber = input('Enter a number:'); switch mynumber case -1 - disp('negative eins'); + disp('negative one'); case 1 - disp('positive eins'); + disp('positive one'); otherwise - disp('etwas anderes'); + disp('something else'); end \end{lstlisting} @@ -1012,15 +1026,271 @@ switch-Anweisung und der case-Anweisung getestet wird. kann immer durch eine \code{if} Anweisung erstezt werden. \end{itemize} + +\subsection{Die Schl\"usselworte \code{break} und \code{continue}} + +Soll die Ausf\"uhrung einer Schleife abgebrochen oder \"ubersprungen +werden, werden die Schl\"usselworte \textbf{break} und +\textbf{continue} eingesetzt (Listing \ref{breakcontinuelisting} +zeigt, wie sie eingesetzt werden k\"onnen). + +\begin{lstlisting}[caption={Ensatz der \code{continue} und \code{break} Schl\"usselworte um die Ausf\"uhrung von Abschnitte in Schleife zu \"uberspringen oder abzubrechen.}, label=breakcontinuelisting] +for x = 1:10 + if(x > 2 & x < 5) + continue; + end + disp(x); +end + +x = 1; +while true + if(x > 5) + break; + end + disp(x); + x = x + 1 +end +\end{lstlisting} + +\begin{exercise}{logicalIndexingBenchmark.m}{logicalIndexingBenchmark.out} + Vergleich von logischem Indizieren und ``manueller'' Auswahl von + Elementen aus einem Vektor. Es wurde oben behauptet, dass die + Auswahl von Elementen mittels logischem Indizieren effizienter + ist. Teste dies indem ein Vektor mit vielen (100000) Zufallszahlen + erzeugt wird aus dem die Elemente gefiltert und gespeichert werden, + die kleiner $0.5$ sind. Umgebe den Programmabschnitt mit den + Br\"udern \code{tic} und \code{toc}. Auf diese Weise misst \matlab{} + die zwischen \code{tic} und \code{toc} vergangene Zeit. + + \begin{enumerate} + \item Benutze eine \code{for} Schleife um die Element auszuw\"ahlen. + \item Benutze logisches Indizieren. + \end{enumerate} +\end{exercise} + +\begin{exercise}{simplerandomwalk.m}{} + Programmiere einen 1-D random walk. Ausgehend von der Startposition + $0$ ``l\"auft'' ein Agent zuf\"allig in die eine oder andere + Richtung. + \begin{itemize} + \item In dem Programm sollen 10 Realisationen eines random walk mit + jeweils 1000 Schritten durchgef\"uhrt werden. + \item Die Position des Objektes ver\"andert sich in jedem Schritt zuf\"allig um + +1 oder -1. + \item Merke Dir alle Positionen. + \item Plotte die Positionen als Funktion der Schrittnummer. + \end{itemize} +\end{exercise} + \section{Skripte und Funktionen} +\subsection{Was ist ein Programm?} -\section{Graphische Darstellung von Daten} -%%% Wuerde ich als eigenes Kapitel machen! JB -%%% In einem separaten Verzeichnis... +Ein Programm ist eine Sammlung von Anweisungen, die in einer Datei auf +dem Rechner abgelegt sind. Wenn es durch den Aufruf zum Leben erweckt +wird, dann wird es Zeile f\"r Zeile von oben nach unten ausgef\"uhrt. + +\matlab{} kennt drei Arten von Programmen: +\begin{enumerate} +\item Skripte +\item Funktionen +\item Objekte (werden wir ignorieren) +\end{enumerate} + +Alle Programme werden in den sogenannten \textit{m-files} gespeichert +(z.B. \textit{meinProgramm.m}). Um sie zu benutzen werden sie von der +Kommandozeile aufgerufen oder in anderen Programmen +verwendet. Programme erh\"ohen die Wiederverwertbarkeit von +Programmcode. Bislang haben wir ausschlie{\ss}lich Skripte +verwendet. Dabei wurde jede Variable, die erzuegt wurde im +\textit{Workspace} abgelegt und konnte wiederverwendet werden. Hierin +liegt allerdings auch eine Gefahr. In der Regel sind Datenanalysen auf +mehrere Skripte verteilt und alle teilen sich den gemeinsamen +Workspace. Verwendet nun ein aufgerufenes Skript eine bereits +definierte Variable und weist ihr einen neuen Wert zu, dann kann das +erw\"unscht und praktisch sein. Wenn es aber unbeabsichtigt passiert +kann es zu Fehlern kommen, die nur sehr schwer erkennbar sind, da ja +jedes Skript f\"ur sich enwandtfrei arbeitet. Eine L\"osung f\"ur +dieses Problem bieten die \textbf{Funktionen}. + +\subsection{Funktionen} + +Eine Funktion in \matlab{} wird \"ahnlich zu einer mathematischen +Funktion definiert: + +\[ y = f(x) \] + +Die Funktion hat einen Namen $f$, sie h\"angt von einem Argument $x$ +ab und liefert ein Ergebnis $y$ zur\"uck. Listing +\ref{functiondefinitionlisting} zeigt wie das in \matlab{} umgesetzt +wird. + +\begin{lstlisting}[caption={Funktionsdefinition in \matlab{}}, label=functiondefinitionlisting] +function [y] = function_name(arg_1, arg_2) +% ^ ^ ^ +% Rueckgabewert Argument_1, Argument_2 +\end{lstlisting} + +Ein Funktion beginnt mit dem Schl\"usselwort \textbf{function} gefolgt +von den R\"uckgabewerte(n), dem Funktionsnamen und (in Klammern) den +Argumenten. Auf den Funktionskopf folgt der auszuf\"uhrende +Programmcode im Funktionsk\"orper. Die Funktionsdefinition wird +optional mit einem \textbf{end} abgeschlossen. Jede Funktion, die vom +Nutzer direkt verwendet werden soll ist in einer eigenen Datei +definiert. \"uber die Definition/Benutzung von Funktionen wird folgendes erreicht: + +\begin{itemize} +\item Kapseln von Programmcode, der f\"ur sich eine Aufgabe l\"ost. +\item Definierte Schnittstelle. +\item Eigener G\"ultigkeitsbereich: + \begin{itemize} + \item Variablen im Workspace sind in der Funktion \textbf{nicht} sichtbar. + \item Variablen, die in der Funktion definiert werden erscheinen + \textbf{nicht} im Workspace. + \end{itemize} +\item Erhöht die Wiederverwendbarkeit von Programmcode. +\item Erh\"oht die Lesbarkeit von Programmen, da sie + \"ubersichtlicher werden. +\end{itemize} + +Das Folgende Beispiel (Listing \ref{badsinewavelisting}) zeigt eine +Funktion, die eine Reihe von Sinusschwingungen unterschiedlicher +Frequenzen berechnet und graphisch darstellt. + +\begin{lstlisting}[caption={Eine Beispielfunktion, die eine Reihe Sinus plottet.},label=badsinewavelisting] +function meine_erste_funktion() % Funktionskopf + t = (0:0.01:2); % hier faengt der Funktionskoerper an + frequenz = 1.0; + amplituden = [0.25 0.5 0.75 1.0 1.25]; + + for i = 1:length(amplituden) + y = sin(frequenz * t * 2 * pi) * amplituden(i); + plot(t, y) + hold on; + end +\end{lstlisting} + +Dieses schlechte Beispiel ist ein Paradebeispiel f\"ur eine schlechte +Funktion. Sie hat folgende Probleme: +\begin{itemize} +\item Der Name ist nicht aussagekr\"aftig. +\item Die Funktion ist f\"ur genau einen Zweck gut. +\item Was sie tut, ist festgelegt und kann von au{\ss}en nicht + beeinflusst werden. +\item Sie tut drei Dinge aus einmal: Sinus berechnen \textbf{und} + Amplituden \"andern \textbf{und} graphisch darstellen. +\item Es ist nicht (einfach) m\"oglich an die berechneten Daten zu + kommen. +\item Keinerlei Dokumentation. Man muss den code lesen um zu + rekonstruieren, was sie tut. +\end{itemize} + +Bevor wir anfangen die Funktion zu verbessern sollten wir uns Gedanken +\"uber das zu l\"osende Problem zu machen: + +\begin{enumerate} +\item Welches Problem soll gel\"ost werden? +\item Aufteilen in Teilprobleme. +\item Gute Namen finden. +\item Definieren der Schnittstellen --- Was muss die Funktion + wissen? Was möchte ich von ihr haben? +\item Daten zur\"uck geben (R\"uckgabewerte definieren). +\end{enumerate} + +Das Beispiel aus Listing \ref{badsinewavelisting} kann in drei +Teilprobleme aufgetrennt werden: +\begin{enumerate} +\item Berechnen der \textbf{einzelnen} Sinus. +\item Plotten der Daten. +\item Koordinieren von Berechung und Darstellung mit + unterschiedlichen Amplituden. +\end{enumerate} + +\begin{lstlisting} +function [t, y] = calculate_sinewave(frequency, amplitude, t_max, t_step) + x = (0:t_step:t_max); + y = sin(frequency * t * 2 * pi) * amplitude; +end +\end{lstlisting} + + +\textbf{2. Plotten einer einzelnen Schwingung:} + +\begin{enumerate} +\item Namen finden +\item Schnittstelle definieren: Was will ich von der Funktion? + Welche Information muss ich ihr geben?\pause + \begin{itemize} + \item Funktion muss wissen: Welche Daten soll sie plotten? Zeitachse, + y-Werte, einen Namen f\"ur die Legende? + \item Muss nichts zur\"uckgeben. + \end{itemize} +\end{enumerate} + +\begin{lstlisting} +function plot_sinewave(x_data, y_data, name) + plot(x_data, y_data, 'displayname', name) +end +\end{lstlisting} + + +\textbf{3. Erstellen eines \textbf{Skriptes} zur Koordinierung:} + +\begin{enumerate} +\item Namen finden +\item Definieren eins Vektors, f\"ur die Amplituden. +\item Definieren einer Variable f\"ur die Frequenz. +\item Definieren der Variablen f\"ur das Maximum und die + Schrittweite der x-Achse. +\item \"Offnen einer neuen Abbildung (\code{figure()}). +\item Setzen des \code{hold on}. +\item \code{for}-Schleife, die über die Amplituden iteriert, die + Sinus berechnen l\"asst und die Resultate an die Plot-Funktion + weiterreicht. +\end{enumerate} + +Skript: \verb+plot_sinewaves.m+ +\begin{lstlisting} +amplitudes = 0.25:0.25:1.25; +frequency = 2; +t_max = 10; +t_step = 0.01; + +figure() +hold on + +for a = amplitudes + name = num2str(a); + [x_data, y_data] = calculate_sinewave(frequency, a, t_max, t_step); + plot_sinewave(x_data, y_data, name) +end +legend('show') +\end{lstlisting} + +\begin{exercise}{}{} + Erweitert das Programm so, dass auch ein Satz von Frequenzen benutzt + wird. +\end{exercise} + +\subsection{Fazit} + +Funktionen sind kleine Code Fragmente, die +\begin{enumerate} +\item ... genau eine Aufgabe erledigen. +\item ... Argumente entgegennehmen k\"onnen. +\item ... R\"uckgabewerte haben k\"onnen. +\item ... ihren eigenen G\"ultigkeitsbereich haben. +\item ... Skripten fast immer vorzuziehen sind. +\end{enumerate} + +Die vorangegangene Diskussion klingt, alsob Skripte zu verteufeln und +zu vermeiden w\"aren. Dem ist nicht so. In Wahrheit sind sie daf''ur +gemacht, Hand in Hand ein Probelm zu l\"osen. W\"ahrend die Funktionen +relativ kleine ``verdauliche'' Teilprobleme l\"osen. Sind die Skripte +daf\"ur gemacht den Rahmen zu bilden und den Ablauf zu koordinieren. +Ein m\"ogliches Programmlayout k\"onnte so aussehen: \begin{figure} - \includegraphics[width=0.9\columnwidth]{convincing} - \caption{Die Folgen schlecht annotierter - Plots. \url{www.xkcd.com}} \label{xkcdplotting} -\end{figure} \ No newline at end of file + \includegraphics[width=0.5\columnwidth]{./images/simple_program.pdf} +\end{figure} +