%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Programming in \matlab} \section{Variables and data types} \subsection{Variables} A \enterm{variable} is a pointer to a certain place in the computer's memory. This pointer is characterized by its name, the variable's name, and the \enterm{data type} (figure~\ref{variablefig}). In the computer's memory the value of the variable is stored in binary form that is as a sequence of zeros and ones (\enterm[Bit]{Bits}). When the variable is read from the memory, this binary pattern is interpreted according to the data type. The example shown in figure~\ref{variablefig} shows that the very same bit pattern is either interpreted as a 8-bit integer type (numeric value 38) or as a ampersand (&) character. In \matlab{} data types are of only minor importance but there are occasions where it becomes important to know the type of a variable and we will come back to them later on. \begin{figure} \centering \begin{subfigure}{.5\textwidth} \includegraphics[width=0.8\textwidth]{variable} \label{variable:a} \end{subfigure}% \begin{subfigure}{.5\textwidth} \includegraphics[width=.8\textwidth]{variableB} \label{variable:b} \end{subfigure} \titlecaption{Variables.}{Variables are point to a memory address. They further are described by their name and data type. The variable's value is stored as a pattern of binary values (0 or 1). When reading the variable this pattern is interpreted according to the variable's data type.}\label{variablefig} \end{figure} \subsection{Creating variables} In \matlab{} variables can be created at any time on the command line or any place in a script or function. Listing~\ref{varListing1} shows three different possibilities: \begin{lstlisting}[label=varListing1, caption={Creating variables.}] >> x = 38 x = 38 >> y = [] y = [] >> z = 'A' z = A \end{lstlisting} Line 1 can be read like: ``create a variable with the name \varcode{x} and assign the value 38''. The equal sign is the so called \codeterm{assignment operator}. Line 5 defines a variable \varcode{y} and assigns an empty value. If not explicitly specified \matlab{} variables will have the \codeterm{double} (a numeric data type, see below) data type. In line 9, however, we create a variable \varcode{z} and assign the character ``A'' to it. Accordingly, \varcode{z} does not have the numeric \codeterm{double} data type but is of the type \codeterm{character}. The actual data type of a variable can be found out with the \code{class()} function. \code{who} prints a list of all defined variables and \code{whos} provides detailed information (listing~\ref{varListing2}). \begin{lstlisting}[label=varListing2, caption={Requesting information about defined variables and their types.}] >>class(x) ans = double >> who Your variables are: x y z >> whos Name Size Bytes Class Attributes x 1x1 8 double y 0x0 0 double z 1x1 2 char \end{lstlisting} \begin{important}[Naming conventions] There are a few rules regarding the variable names. \matlab{} is case-sensitive, i.e. \code{x} and \code{X} are two different names. Names must begin with an alphabetic character. German (or other) umlauts, special characters and spaces are forbidden. \end{important} \subsection{Working with variables} We can certainly work, i.e. do calculations, with variables. \matlab{} knows all basic \codeterm[Operator!arithmetic]{arithmetic operators} such as \code[Operator!arithmetic!1add@+]{+}, \code[Operator!arithmetic!2sub@-]{-}, \code[Operator!arithmetic!3mul@*]{*} and \code[Operator!arithmetic!4div@/]{/}. The power is denoted by the \code[Operator!arithmetic!5pow@\^{}]{\^{}}. Listing~\ref{varListing3} show their use. \pagebreak[4] \begin{lstlisting}[label=varListing3, caption={Working with variables.}] >> x = 1; >> x + 10 ans = 11 >> x % x has not changed! ans = 1 >> y = 2; >> x + y ans = 3 >> z = x + y z = 3 >> z = z * 5; >> z z = 15 >> clear z % deleting a variable \end{lstlisting} Note: in lines 2 and 6 the values of the variables have been used without changing their values. Whenever the value of a variable should change, the \code[Operator!Assignment!=]{=} operator has to be used (lines 14 and 18). Line 23, finally shows how to delete a variable. \subsection{Data types} As mentioned above, the data type associated with a variable defines how the stored bit pattern is interpreted. The major data types are: \begin{itemize} \item \codeterm{integer}: Integer numbers. There are several subtypes which, for most use-cases, can be ignored when working in \matlab{}. \item \codeterm{double}: Floating point numbers. In contrast to the real numbers that are represented with this data type the number of numeric values that can be represented is limited (countable?). \item \codeterm{complex}: Complex numbers having a real and imaginary part. \item \codeterm{logical}: Boolean values that can be evaluated to \code{true} or \code{false}. \item \codeterm{char}: ASCII characters. \end{itemize} There is a variety of numeric data types that require different memory demands and ranges of representable values (table~\ref{dtypestab}). \begin{table}[t] \centering \titlecaption{Numeric data types and their ranges.}{} \label{dtypestab} \begin{tabular}{llcl}\hline Data type & memory demand & range & example \erh \\ \hline \code{double} & 64 bit & $\approx -10^{308}$ to $\approx 10^{308} $& Floating point numbers.\erb\\ \code{int} & 64 bit & $-2^{31}$ to $2^{31}-1$ & Integer values. \\ \code{int16} & 16 bit & $-2^{15}$ to $2^{15}-1$ & Digitizes measurements. \\ \code{uint8} & 8 bit & $0$ bis $255$ & Digitized intensities of colors in images. \\ \hline \end{tabular} \end{table} By default \matlab{} uses the \codeterm{double} data type whenever numerical values have to be stored. Nevertheless there are use-cases in which different data types are better suited. Box~\ref{daqbox} exemplifies such a case. \begin{ibox}[t]{\label{daqbox}Digitizing measurements} Scenario: The electric activity (e.g. the membrane potential) of a nerve cell is recorded. The measurements are digitized and stored on the hard disk of a computer for later analysis. This is done using a Data Acquisition system (DAQ) that converts the analog measurements into computer digestible digital format. Typically these systems have a working range of $\pm 10$\,V. This range is usually resolved with a precision of 16 bit. This means that the full potential range is mapped onto $2^{16}$ digital values.\vspace{0.25cm} \begin{minipage}{0.5\textwidth} \includegraphics[width=0.9\columnwidth]{data_acquisition} \end{minipage} \begin{minipage}{0.5\textwidth} Mapping of the potential range onto a \code{int16} data type: \[ y = x \cdot 2^{16}/20\] with $x$ being the measured potential and $y$ the digitized value at a potential range of $\pm10$\,V and a resolution of 16 bit. Resulting values are integer numbers in the range $-2^{15}=-32768$ to $2^{15}-1 = 32767$. The measured potential can be calculated from the digitized value by inverting the equation: \[ x = y \cdot 20/2^{16} \] \end{minipage}\vspace{0.25cm} In this context it is most efficient to store the measured values as \code{int16} instead of \code{double} numbers. Storing floating point numbers requires four times more memory (8 instead of 2 \codeterm{Byte}, 64 instead of 16 bit) and offers no additional information. \end{ibox} \section{Vectors and matrices} Vectors and matrices are the most important data structures in \matlab{}. In other programming languages there is no distinction between theses structures, they are one- or multidimensional \enterm{arrays}. Such arrays are structures that can store multiple values of the same data type in a single variable. Due to \matlab{}'s origin in the handling of mathematical problems, they have different name but are internally the same. Vectors are 2-dimensional matrices in which one dimension has the size 1 (a singleton dimension). \subsection{Vectors} In contrast to variables that store just a single value (\enterm{scalar}) a vector can store multiple values of the same data type (figure~\ref{vectorfig}). The variable \varcode{a} for example stores four integer values. \begin{figure} \includegraphics[width=0.8\columnwidth]{scalarArray} \titlecaption{Scalars and vectors.}{\textbf{A)} A scalar variable holds exactly on value. \textbf{B)} A vector can hold multiple values. These must be of the same data type (e.g. integer numbers). \matlab{} distinguishes between row- and column-vectors.}\label{vectorfig} \end{figure} The following listing (\ref{generatevectorslisting} shows how vectors can be created. In lines 5 and 9 the \code[Operator!Matrix!:]{:} notation is used to easily create vectors with many elements or with step-sizes unequal to 1. Line 5 can be read like: ``Create a variable \varcode{b} and assign the values from 0 to 9 in increasing steps of 1.''. Line 9 reads: ``Create a variable \varcode{c} and assign the values from 0 to 10 in steps of 2''. \begin{lstlisting}[label=generatevectorslisting, caption={Creating simple row-vectors.}] >> a = [0 1 2 3 4 5 6 7 8 9] % Creating a row-vector a = 0 1 2 3 4 5 6 7 8 9 >> b = (0:9) % more comfortable b = 0 1 2 3 4 5 6 7 8 9 >> c = (0:2:10) c = 0 2 4 6 8 10 \end{lstlisting} The length of a vector, that is the number of elements, can be requested using the \code{length()} or \code{numel()} functions. \code{size()} provides the same information in a slightly, yet more powerful way (listing~\ref{vectorsizelisting}). The above used vector \varcode{a} has the following size: \begin{lstlisting}[label=vectorsizeslisting, caption={Size of a vector.}] >> length(a) ans = 10 >> size(a) ans = 1 10 \end{lstlisting} The answer provided by the \code{size()} function demonstrates that vectors are nothing else but 2-dimensional matrices in which one dimension has the size 1 (singleton dimension). \code[length()]{length(a)} in line 1 just returns the size of the largest dimension. Listing~\ref{columnvectorlisting} shows how to create a column-vector and how the \code[Operator!Matrix!']{'} --- operator is used to transpose the column-vector into a row-vector (lines 14 and following). \begin{lstlisting}[label=columnvectorlisting, caption={Column-vectors.}] >> b = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] % Creating a column-vector b = 1 2 ... 9 10 >> length(b) ans = 10 >> size(b) ans = 10 1 >> b = b' % Transpose b = 1 2 3 4 5 6 7 8 9 10 >> size(b) ans = 1 10 \end{lstlisting} \subsubsection{Accessing elements of a vector} \begin{figure} \includegraphics[width=0.4\columnwidth]{arrayIndexing} \titlecaption{Index.}{Each element of a vector can be addressed via its index (small numbers) to access its content (large numbers).}\label{vectorindexingfig} \end{figure} The content of a vector is accessed using the element's index (figure~\ref{vectorindexingfig}). Each element has an individual \codeterm{index} that ranges (int \matlab{}) from 1 to the number of elements irrespective of the type of vector. \begin{important}[Indexing] Elements of a vector are accessed via their index. This process is called \codeterm{indexing}. In \matlab{} the first element has the index one. The last element's index equals the length of the vector. \end{important} Listings~\ref{vectorelementslisting} and~\ref{vectorrangelisting} show how the index is used to access elements of a vector. One can access individual values by providing a single index or use the \code[Operator!Matrix!:]{:} notation to access multiple values with a single command. \begin{lstlisting}[label=vectorelementslisting, caption={Access to individual elements of a vector.}] >> a = (11:20) a = 11 12 13 14 15 16 17 18 19 20 >> a(1) % the 1. element ans = 11 >> a(5) % the 5. element ans = 15 >> a(end) % the last element ans = 20 \end{lstlisting} \begin{lstlisting}[caption={Access to multiple elements.}, label=vectorrangelisting] >> a([1 3 5]) % 1., 3. and 5. element ans = 11 13 15 >> a(2:4) % all elements with the indices 2 to 4 ans = 12 13 14 >> a(1:2:end) % every second element ans = 11 13 15 17 19 >> a(:) % all elements as row-vector ans = 11 12 13 14 15 16 17 18 19 20 \end{lstlisting} \begin{exercise}{vectorsize.m}{vectorsize.out} Create a row-vector \varcode{a} with 5 elements. The return value of \code[size()]{size(a)} is a again a vector with the length 2. How could you find out the size of the \varcode{a} in the 2nd dimension? \end{exercise} \subsubsection{Operations with vectors} Similarly to the scalar variables discussed above we can work with vectors and do calculations. Listing~\ref{vectorscalarlisting} shows how vectors and scalars can be combined with the operators \code[Operator!arithmetic!1add@+]{+}, \code[Operator!arithmetic!2sub@-]{-}, \code[Operator!arithmetic!3mul@*]{*}, \code[Operator!arithmetic!4div@/]{/} \code[Operator!arithmetic!5powe@.\^{}]{.\^}. \begin{lstlisting}[caption={Cancluating with vectors and scalars.},label=vectorscalarlisting] >> a = (0:2:8) a = 0 2 4 6 8 >> a + 5 % adding a scalar ans = 5 7 9 11 13 >> a - 5 % subtracting a scalar ans = -5 -3 -1 1 3 >> a * 2 % multiplication ans = 0 4 8 12 16 >> a / 2 % division ans = 0 1 2 3 4 >> a .^ 2 % exponentiation ans = 0 4 16 36 64 \end{lstlisting} When calculating with scalars and vectors the same mathematical operation is done to each element of the vector. In case of, e.g. an addition this is called an element-wise addition. Care has to be taken when you do calculations with two vectors. For element-wise operations of two vectors, e.g. each element of vector \varcode{a} should be added to the respective element of vector \varcode{b} the two vectors must have the same length and the same layout (row- or column vectors). Addition and subtraction are always element-wise (listing~\ref{vectoradditionlisting}). \begin{lstlisting}[caption={Element-wise addition and subtraction of two vectors.},label=vectoradditionlisting] >> a = [4 9 12]; >> b = [4 3 2]; >> a + b % addition ans = 8 12 14 >> a - b % subtraction ans = 0 6 10 >> c = [8 4]; >> a + c % both vectors must have the same length! Error using + Matrix dimensions must agree. >> d = [8; 4; 2]; >> a + d % both vectors must have the same layout! Error using + Matrix dimensions must agree. \end{lstlisting} Element-wise multiplication and division and exponentiation requires a different operator with preceding '.'. \matlab{} defines the following operators for element-wise operations on vectors \code[Operator!arithmetic!3mule@.*]{.*}, \code[Operator!arithmetic!4dive@./]{./} and \code[Operator!arithmetic!5powe@.\^{}]{.\^{}} (listing~\ref{vectorelemmultiplicationlisting}). \begin{lstlisting}[caption={Element-wise multiplication, division and exponentiation of two vectors.},label=vectorelemmultiplicationlisting] >> a .* b % element-wise multiplication ans = 16 27 24 >> a ./ b % element-wise division ans = 1 3 6 >> a ./ b % element-wise exponentiation ans = 256 729 144 >> a .* c % both vectors must have the same size! Error using .* Matrix dimensions must agree. >> a .* d % Both vectors must have the same layout! Error using .* Matrix dimensions must agree. \end{lstlisting} The simple operators \code[Operator!arithmetic!3mul@*]{*}, \code[Operator!arithmetic!4div@/]{/} and \code[Operator!arithmetic!5pow@\^{}]{\^{}} execute the respective matrix-operations known from linear algebra (Box~ \ref{matrixmultiplication}). As a special case is the multiplication of a row-vectors $\vec a$ with a column-vector $\vec b$ the scalar-poduct (or dot-product) $\sum_i = a_i b_i$. \begin{lstlisting}[caption={Multiplication of vectors.},label=vectormultiplicationlisting] >> a * b % multiplication of two vectors Error using * Inner matrix dimensions must agree. >> a' * b' % multiplication of column-vectors Error using * Inner matrix dimensions must agree. >> a * b' % multiplication of a row- and column-vector ans = 67 >> a' * b % multiplication of a column- and a row-vector ans = 16 12 8 36 27 18 48 36 24 \end{lstlisting} \pagebreak[4] To remove elements from a vector an empty value (\code[Operator!Matrix!{[]}]{[]}) is assigned to the respective elements: \begin{lstlisting}[label=vectoreraselisting, caption={Deleting elements of a vector.}] >> a = (0:2:8); >> length(a) ans = 5 >> a(1) = [] % delete the 1st element a = 2 4 6 8 >> a([1 3]) = [] % delete the 1st and 3rd element a = 4 8 >> length(a) ans = 2 \end{lstlisting} In addition to deleting of vector elements one also add new elements or concatenate two vectors. When performing a concatenation the two concatenated vectors must match in their layout (listing~\ref{vectorinsertlisting}, Line 11). To extend a vector we can simply assign values beyond the end of the vector (line 21 in listing~ \ref{vectorinsertlisting}). \matlab{} will automatically adjust the variable. This way of extending a vector on-the-fly is however expensive. In the background \matlab{} has to reserve new memory of the appropriate size and then copies the contents into it. If possible this should be avoided (the \matlab{} editor will warn you). \begin{lstlisting}[caption={Concatenation and extension of vectors.}, label=vectorinsertlisting] >> a = [4 3 2 1]; >> b = [10 12 14 16]; >> c = [a b] % create a new vector by concatenation c = 4 3 2 1 10 12 14 16 >> length(c) ans = 8 >> length(a) + length(b) ans = 8 >> c = [a b']; % vector layouts must match Error using horzcat Dimensions of matrices being concatenated are not consistent. >> a(1:3) = [5 6 7] % assign new values to elements of the vector a = 5 6 7 1 >> a(1:3) = [1 2 3 4]; % range of elements and number of new values must match In an assignment A(I) = B, the number of elements in B and I must be the same. >> a(3:6) = [1 2 3 4] % extending a vector by assigning beyond its bounds a = 5 6 1 2 3 4 \end{lstlisting} \subsection{Matrices} Vectors are a special case of the more general data structure, i.e. the matrix. Vectors are matrices in which one dimension is a singleton dimension (length of 1). While matrices can have an almost arbitrary number of dimensions the most common matrices are 2-3 dimensional (figure~\ref{matrixfig} A, B). \begin{figure} \includegraphics[width=0.5\columnwidth]{matrices} \titlecaption{Matrices.}{\textbf{A)} 2-dimensional matrix with the name ``test''. \textbf{B)} Illustration of a 3-dimensional matrix. Arrows indicate the rank across the dimensions.}\label{matrixfig} \end{figure} Matrices can be created similarly to vectors (listing~\ref{matrixlisting}). The definition of a matrix is enclosed into the square braces \code[Operator!Matrix!{[]}]{[]} the semicolon operator \code[Operator!Matrix!;]{;} separates the individual rows of a matrix. \begin{lstlisting}[label=matrixlisting, caption={Creating matrices.}] >> a = [1 2 3; 4 5 6; 7 8 9] >> a = 1 2 3 4 5 6 7 8 9 >> b = ones(3, 4, 2) b(:,:,1) = 1 1 1 1 1 1 1 1 1 1 1 1 b(:,:,2) = 1 1 1 1 1 1 1 1 1 1 1 1 \end{lstlisting} The notation shown in line 1 is not suited to create matrices of higher dimensions. For these, \matlab{} provides a number of creator-functions that help creating n-dimensional matrices (e.g. \code{ones()}, line 7 called with 3 arguments creates a 3-D matrix). The function \code{cat()} allows to concatenate n-dimensional matrices. To request the length of a vector we used the function \code{length()}. This function is no longer suited to request information about the size of a matrix. As mentioned above, \code{length()} would return the length of the largest dimension. The function \code{size()} however, returns the length in each dimension and should be always preferred over \code{length()}. \begin{figure} \includegraphics[width=0.9\columnwidth]{matrixIndexing} \titlecaption{Indices in matrices.}{Each element of a matrix is identified by its index. The index is a tuple of as many numbers as the matrix has dimensions. The first coordinate in this tuple counts the row, the second the column and the third the page, etc. }\label{matrixindexingfig} \end{figure} Analogous to the element access in vectors we can address individual elements of a matrix by it's index. Similar to a coordinate system each element is addressed using a n-tuple whit n the number of dimensions (figure~\ref{matrixindexingfig}, listing~\ref{matrixIndexing}). This type of indexing is called \codeterm{subscript indexing}. The first coordinate refers always to the row, the second to the column, the third to the page, and so on. \begin{lstlisting}[caption={Indexing in matrices, Indizierung.}, label=matrixIndexing] >> x=rand(3, 4) % 2-D matrix filled with random numbers x = 0.8147 0.9134 0.2785 0.9649 0.9058 0.6324 0.5469 0.1576 0.1270 0.0975 0.9575 0.9706 >> size(x) ans = 3 4 >> x(1,1) % top left corner ans = 0.8147 >> x(2,3) % element in the 2nd row, 3rd column ans = 0.5469 >> x(1,:) % the first row ans = 0.8147 0.9134 0.2785 0.9649 >> x(:,2) % second column ans = 0.9134 0.6324 0.0975 \end{lstlisting} Subscript indexing is very intuitive but offers not always the most straight-forward solution to the problem. Consider for example that you have a 3-D matrix and you want the minimal number in that matrix. An alternative way is the so called \emph{linar indexing} in which each element of the matrix is addressed by a single number. The linear index thus ranges from 1 to \code{numel(matrix)}. The linear index increases first along the 1st, 2nd, 3rd etc. dimension (figure~\ref{matrixlinearindexingfig}). It is not as intuitive but can be really helpful (listing~\ref{matrixLinearIndexing}). \begin{figure} \includegraphics[width=0.9\columnwidth]{matrixLinearIndexing} \titlecaption{Linear indexing in matrices.}{The linear index in a matrix increases from 1 to the number of elements in the matrix. It increases first along the first dimension, then the rows in each column and so on.}\label{matrixlinearindexingfig} \end{figure} \begin{lstlisting}[label=matrixLinearIndexing, caption={Lineares indexing in matrices.}] >> x = randi(100, [3, 4, 5]); % 3-D matrix filled with random numbers >> size(x) ans = 3 4 5 >> numel(x) ans = 60 >> min(min(min(x))) % minimum across rows, then columns, then pages ans = 4 >> min(x(1:numel(x))) % or like this ans = 4 >> min(x(:)) % or even simpler ans = 4 \end{lstlisting} \begin{ibox}[t]{\label{matrixmultiplication} The matrix-multiplication.} The matrix-multiplication from linear algebra is \textbf{not} an element-wise multiplication of each element in a matrix \varcode{A} and the respective element from matrix \varcode{B}. It is something completely different. Confusing element-wise and matrix-multiplication is one of the most common mistakes in \matlab{}. \linebreak The matrix-multiplication is only possible if the number of columns in the first matrix agrees with the number of rows in the other. More formal: $\mathbf{A}$ and $\mathbf{B}$ can be multiplied $(\mathbf{A} \cdot \mathbf{B})$, if $\mathbf{A}$ has the size $(m \times n)$ and $\mathbf{B}$ the size $(n \times k)$. The multiplication is possible if the \enterm{inner dimensions} $n$ agree. Then, the elements $c_{i,j}$ of the product $\mathbf{C} = \mathbf{A} \cdot \mathbf{B}$ are given as the scalar product (dot-product) of each row in $\mathbf{A}$ with each column in $\mathbf{B}$: \[ c_{i,j} = \sum_{k=1}^n a_{i,k} \; b_{k,j} \; . \] The matrix-multiplication is not commutative, that is: \[ \mathbf{A} \cdot \mathbf{B} \ne \mathbf{B} \cdot \mathbf{A} \; . \] Consider the matrices: \[\mathbf{A}_{(3 \times 2)} = \begin{pmatrix} 1 & 2 \\ 5 & 4 \\ -2 & 3 \end{pmatrix} \quad \text{and} \quad \mathbf{B}_{(2 \times 2)} = \begin{pmatrix} -1 & 2 \\ -2 & 5 \end{pmatrix} \; . \] The inner dimensions of these matrices match ($(3 \times 2) \cdot (2 \times 2)$) and the product of $\mathbf{C} = \mathbf{A} \cdot \mathbf{B}$ can be calculated. Following from the number of rows in $\mathbf{A}$ (3) and the number of columns in $\mathbf{B}$ (2) the resulting matrix $\mathbf{C}$ will have the size $(3 \times 2)$: \[ \mathbf{A} \cdot \mathbf{B} = \begin{pmatrix} 1 \cdot -1 + 2 \cdot -2 & 1 \cdot 2 + 2\cdot 5 \\ 5 \cdot -1 + 4 \cdot -2 & 5 \cdot 2 + 4 \cdot 5\\ -2 \cdot -1 + 3 \cdot -2 & -2 \cdot 2 + 3 \cdot 5 \end{pmatrix} = \begin{pmatrix} -5 & 12 \\ -13 & 30 \\ -4 & 11\end{pmatrix} \; . \] The product of $\mathbf{B} \cdot \mathbf{A}$, however, is not defined since the inner dimensions do not agree ($(2 \times 2) \cdot (3 \times 2)$). \end{ibox} Calculations on matrices apply the same rules as the calculations with vectors. Element-wise computations are possible as long as the matrices have the same dimensionality. It is again important to distinguish between the element-wise (\code[Operator!arithmetic!3mule@.*]{.*} operator, listing \ref{matrixOperations} line 10) and the operator for matrix-multiplication (\code[Operator!arithmetic!3mul@*]{*}, listing~\ref{matrixOperations} lines 14, 17 and 21, box~\ref{matrixmultiplication}). To do a matrix-multiplication the inner dimensions of the matrices have to agree (box~\ref{matrixmultiplication}). \pagebreak[4] \begin{lstlisting}[label=matrixOperations, caption={Two kinds of multiplications of matrices.}] >> A = randi(5, [2, 3]) % 2-D matrix A = 1 5 3 3 2 2 >> B = randi(5, [2, 3]) % dto. B = 4 3 5 2 4 5 >> A .* B % element-wise multiplication ans = 4 15 15 6 8 10 >> A * B % invalid matrix-multiplication Error using * Inner matrix dimensions must agree. >> A * B' % valid matrix-multiplication ans = 34 37 28 24 >> A' * B % matrix-multiplication is not commutative ans = 10 15 20 24 23 35 16 17 25 \end{lstlisting} \section{Boolean Operations} Boolesche Ausdr\"ucke sind Anweisungen, die zu \codeterm{wahr} oder \codeterm{falsch} ausgewertet werden. Man kennt sie z.B. aus der Mengenlehre. In der Programmierung werden sie eingesetzt, um z.B. die Beziehung zwischen Entit\"aten zu testen. Hierzu werden die \codeterm{relationalen Operatoren} (\code[Operator!relationaler!>]{>}, \code[Operator!relationaler!<]{<}, \code[Operator!relationaler!==]{==}, \code[Operator!relationaler!"!]{!}, gr\"o{\ss}er als, kleiner als, gleich und nicht) eingesetzt. Mehrere Ausdr\"ucke werden mittels der \codeterm[Operator!logischer]{logischen Operatoren} (\code[Operator!logischer!and1@\&]{\&}, \code[Operator!logischer!or1@{"|} {}]{|}, UND, ODER) verkn\"upft. Sie sind nicht nur wichtig, um Codeabschnitte bedingt auszuf\"uhren (Verzweigungen, \ref{controlstructsec}) sondern auch um aus Vektoren und Matrizen bequem Elemente auszuw\"ahlen (logisches Indizieren, \ref{logicalindexingsec}). Die Tabellen \ref{logicalandor} zeigen die Wahrheitstabellen f\"ur das logische UND, das logische ODER und das logische XOR (entweder-oder). Es werden die Aussagen A und B mit dem Operator verkn\"upft. Beim logischen UND ist der gesamte Ausdruck nur dann wahr, wenn beide Ausdr\"ucke sich zu wahr auswerten lassen. Anders ist das beim logischen ODER. Hier ist der gesamte Ausdruck wahr, wenn sich der eine \emph{oder} der andere Ausdruck, oder beide Ausdr\"ucke zu wahr auswerten lassen. Das auschlie{\ss}ende ODER (XOR) ist nur wahr, wenn entweder der eine oder der andere Ausdruck wahr ist und ist in \matlab{} als Funktion \code[xor()]{xor(A, B)} verf\"ugbar. \begin{table}[tp] \titlecaption{Wahrheitstabellen logisches UND, ODER und XOR.}{}\label{logicalandor} \begin{tabular}{llll} \multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\ & \sffamily{\textbf{und}} & \multicolumn{1}{|c}{wahr} & falsch \\ \cline{2-4} \multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch} \erb \\ & \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{red}{falsch}} & \textcolor{red}{falsch} \end{tabular} \hfill \begin{tabular}{llll} \multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\ & \sffamily{\textbf{oder}} & \multicolumn{1}{|c}{wahr} & falsch \\ \cline{2-4} \multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c}{\textcolor{mygreen}{wahr}} & \textcolor{mygreen}{wahr} \erb \\ & \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch} \end{tabular} \hfill \begin{tabular}{llll} \multicolumn{2}{l}{\multirow{2}{*}{}} & \multicolumn{2}{c}{\textbf{B}} \\ & \sffamily{\textbf{xor}} & \multicolumn{1}{|c}{wahr} & falsch \\ \cline{2-4} \multirow{2}{*}{\textbf{A}} & \multicolumn{1}{l|}{wahr} & \multicolumn{1}{c}{\textcolor{red}{falsch}} & \textcolor{mygreen}{wahr} \erb \\ & \multicolumn{1}{l|}{falsch} & \multicolumn{1}{l}{\textcolor{mygreen}{wahr}} & \textcolor{red}{falsch} \end{tabular} \end{table} Tabelle \ref{logicalrelationaloperators} zeigt die logischen Operatoren, die in \matlab{} definiert sind. Zu bemerken sind hier noch die \code[Operator!logischer!and2@\&\&]{\&\&} und \code[Operator!logischer!or2@{"|}{"|} {}]{||} Operatoren. Man kann beliebige Ausdr\"ucke verkn\"upfen und h\"aufig kann schon anhand des ersten Ausdrucks entschieden werden, ob der gesamte boolesche Ausdruck zu wahr oder falsch ausgewertet werden wird. Wenn zwei Aussagen mit einem UND verkn\"upft werden und der erste zu falsch ausgewertet wird, muss der zweite gar nicht mehr gepr\"uft werden. Die Verwendung der \enterm{short-circuit} Versionen spart Rechenzeit, da die Ausdr\"ucke nur sowei wie n\"otig ausgewertet werden. \begin{table}[t] \titlecaption{\label{logicalrelationaloperators} Logische (links) und relationale (rechts) Operatoren in \matlab.}{} \begin{tabular}{cc} \hline \textbf{Operator} & \textbf{Beschreibung} \erh \\ \hline \varcode{$\sim$} & logisches NICHT \erb \\ \varcode{$\&$} & logisches UND\\ \varcode{$|$} & logisches ODER\\ \varcode{$\&\&$} & short-circuit logisches UND\\ \varcode{$\|$} & short-circuit logisches ODER\\ \hline \end{tabular} \hfill \begin{tabular}{cc} \hline \textbf{Operator} & \textbf{Beschreibung} \erh \\ \hline \varcode{$==$} & gleich \erb \\ \varcode{$\sim=$} & ungleich\\ \varcode{$>$} & gr\"o{\ss}er als \\ \varcode{$<$} & kleiner als \\ \varcode{$>=$} & gr\"o{\ss}er oder gleich \\ \varcode{$<=$} & kleiner oder gleich \\ \hline \end{tabular} \end{table} Um Werte miteinander zu vergleichen gibt es die \codeterm[Operator!relationaler]{relationalen Operatoren} (Tabelle \ref{logicalrelationaloperators}). Mit ihnen kann man auf Dinge wie Gleichheit (\varcode{==}) gr\"o{\ss}er oder kleiner als (\varcode{>}, \varcode{<}) testen. \begin{important}[Zuweisungs- und Gleichheitsoperator] Der Zuweisungsoperator \code[Operator!Zuweisung!=]{=} und der logische Operator \code[Operator!logischer!==]{==} sind zwei grundverschiedene Dinge. Da sie umgangsprachlich gleich sind k\"onnen sie leider leicht verwechselt werden. \end{important} Das Ergebnis eines booleschen Ausdrucks ist immer vom Datentyp \codeterm{logical}. Jede beliebige Variable zu wahr oder falsch ausgewertet werden indem diese in den Typ \code{logical} umgewandelt wird. Dabei werden von \matlab{} alle Werte, die nicht 0 sind als wahr eingesch\"atzt. Listing \ref{booleanexpressions} zeigt einige Beispiele. \matlab{} kennt die Schl\"usselworte \code{true} und \code{false}. Diese sind Synonyme f\"ur die \code{logical} Werte 1 und 0. \begin{lstlisting}[caption={Boolesche Ausdr\"ucke.}, label=booleanexpressions] >> true ans = 1 >> false ans = 0 >> logical(1) ans = 1 >> 1 == true ans = 1 >> 1 == false ans = 0 >> logical('test') ans = 1 1 1 1 >> 1 > 2 ans = 0 >> 1 < 2 ans = 1 >> x = [2 0 0 5 0] & [1 0 3 2 0] x = 1 0 0 1 0 >> ~([2 0 0 5 0] & [1 0 3 2 0]) ans = 0 1 1 0 1 >> [2 0 0 5 0] | [1 0 3 2 0] ans = 1 0 1 1 0 \end{lstlisting} \section{Logisches Indizieren}\label{logicalindexingsec} Einer der wichtigsten Einsatzorte f\"ur boolesche Ausdr\"ucke ist das logische Indizieren. Logisches Indizieren ist eines der Schl\"usselkonzepte in \matlab{}. Nur mit diesem k\"onnen Filteroperationen auf Vektoren und Matrizen effizient durchgef\"uhrt werden. Es ist sehr m\"achtig und, wenn es einmal verstanden wurde, sehr intuitiv zu benuzten. Das Grundkonzept hinter der logischen Indizierung ist, dass durch die Verwendung eines booleschen Ausdrucks auf z.B. einen Vektor ein logischer Vektor gleicher Gr\"o{\ss}e zur\"uckgegeben wird. Dieser wird benutzt um die Elemente des urspr\"unglichen Vektors auszuw\"ahlen, bei denen der logische Vektor \codeterm{wahr} ist (Listing \ref{logicalindexing1}). Zeile 14 kann wie folgt gelesen werden: Gib die Elemente von \varcode{x} an den Stellen, an denen \varcode{x < 0} wahr ist, zur\"uck. \begin{lstlisting}[caption={Beispiel logisches Indizieren.}, label=logicalindexing1] >> x = randn(1, 6) % Zeilenvektor mit 6 Zufallszahlen x = -1.4023 -1.4224 0.4882 -0.1774 -0.1961 1.4193 >> % logisches Indizieren in zwei Schritten: >> x_smaller_zero = x < 0 % logischer Vektor x_smaller_zero = 1 1 0 1 1 0 >> elements_smaller_zero = x(x_smaller_zero) % benutzen, um zuzugreifen elements_smaller_zero = -1.4023 -1.4224 -0.1774 -0.1961 >> % logisches Indizieren in einem Schritten: >> elements_smaller_zero = x(x < 0) elements_smaller_zero = -1.4023 -1.4224 -0.1774 -0.1961 \end{lstlisting} \begin{exercise}{logicalVector.m}{logicalVector.out} Erstelle einen Vektor \varcode{x} mit den Werten 0--10. \begin{enumerate} \item F\"uhre aus: \varcode{y = x < 5} \item Gib den Inhalt von \varcode{y} auf dem Bildschirm aus. \item Was ist der Datentyp von \varcode{y}? \item Gibt alle Elemente aus \varcode{x} zur\"uck, die kleiner als 5 sind. \end{enumerate} \pagebreak[4] \end{exercise} \begin{figure}[t] \includegraphics[width= 0.9\columnwidth]{logicalIndexingTime} \titlecaption{Beispiel f\"ur logisches Indizieren.} {Der rot markierte Abschnitt aus den Daten wurde indirekt mit logischem Indizieren auf dem Zeitvektor ausgew\"ahlt (\varcode{x(t > 5 \& t < 6)}).}\label{logicalindexingfig} \end{figure} Logisches Indizieren wurde oben so benutzt, dass die Auswahl auf dem Inhalt desselben Vektors beruhte. Ein weiterer sehr h\"aufiger Fall ist jedoch, dass die Auswahl aus einem Vektor auf dem Inhalt eines zweiten Vektors basiert. Ein Beispiel ist, dass \"uber einen gewissen Zeitraum Daten aufgenommen werden und aus diesen die Daten eines bestimmten Zeitraums ausgew\"ahlt werden sollen (\figref{logicalindexingfig}). \begin{exercise}{logicalIndexingTime.m}{} Angenommen es werden \"uber einen bestimmten Zeitraum Messwerte genommen. Bei solchen Messungen erh\"alt man einen Vektor, der die Zeitpunkte der Messung speichert und einen zweiten mit den jeweiligen Messwerten. \begin{itemize} \item Erstelle einen Vektor \varcode{t = 0:0.001:10;}, der die Zeit repr\"asentiert. \item Erstelle einen zweiten Vektor \varcode{x} mit Zufallszahlen, der die gleiche L\"ange hat wie \varcode{t}. Die Werte darin stellen Messungen zu den Zeitpunkten in \varcode{t} dar. \item Benutze logische Indizieren um die Messwerte auszuw\"ahlen, die dem zeitlichen Abschnitt 5--6\,s entsprechen. \end{itemize} \end{exercise} \section{Kontrollstrukturen}\label{controlstructsec} In der Regel wird ein Programm Zeile f\"ur Zeile von oben nach unten ausgef\"uhrt. Manchmal muss der Kontrollfluss aber so gesteuert werden, dass bestimmte Teile wiederholt oder nur unter bestimmten Bedingungen ausgef\"uhrt werden sollen. Von gro{\ss}er Bedeutung sind hier zwei Strukturen: \begin{enumerate} \item Schleifen. \item Bedingte Anweisungen und Verzweigungen. \end{enumerate} \subsection{Schleifen} Schleifen werden gebraucht um wiederholte Ausf\"uhrung desselben Codes zu vereinfachen. In einer \"Ubung wurde die Fakult\"at von 5 wie in Listing \ref{facultylisting} berechnet: \begin{lstlisting}[caption={Berechnung der Fakult\"at von 5 in f\"unf Schritten}, label=facultylisting] >> x = 1; >> x = x * 2; >> x = x * 3; >> x = x * 4; >> x = x * 5; >> x x = 120 \end{lstlisting} Im Prinzip ist das obige Programm v\"ollig in Ordnung. Es f\"allt jedoch auf, dass die Zeilen 2 bis 5 sehr \"ahnlich sind; bis auf die Multiplikation mit einer ansteigenden Zahl \"andert sich nichts. Die Verwendung von mehr oder weniger exakten Wiederholungen einzelner Zeilen oder ganzer Abschnitte ist schlechter Prgrammierstil. Dabei geht es nicht nur um einen \"asthetischen Aspekt sondern vielmehr darum, dass es schwerwiegende Nachteile gibt: \begin{enumerate} \item Fehleranf\"alligkeit: Beim ``Copy-and-paste'' kann leicht vergessen werden in einzelnen Wiederholungen die entscheidende \"Anderung auch wirklich vorzunehmen. \shortquote{Copy and paste is a design error.}{David Parnas} \item Flexibilit\"at: Das obige Programm ist f\"ur genau einen Zweck, Berechnung der Fakult\"at von f\"unf, gemacht und kann nichts anderes. \item Wartung: Wenn ein Fehler gemacht wurde, dann muss der Fehler in allen Wiederholungen korrigiert werden (sehr leicht wird dabei etwas \"ubersehen). \item Verst\"andlichkeit: Solche Abschnitte sind schwerer zu lesen und schwer zu verstehen. Das liegt zum Teil daran, dass man dazu neigt \"uber sich wiederholende Zeilen zu springen (ist ja eh das gleiche...) und dann den entscheidenden Teil verpasst. Zum Anderen f\"uhrt Codeduplication zu langen, un\"ubersichtlichen Programmen. \end{enumerate} Alle Programmiersprachen bieten zur L\"osung dieses Problems die Schleifen. Eine Schleife wird immer dann eingesetzt, wenn Abschnitte wiederholt ausgef\"uhrt werden sollen. \subsubsection{Die \code{for} -- Schleife} Der am h\"aufigsten benutzte Vertreter der Schleifen ist die \codeterm{for-Schleife}. Sie besteht aus dem \codeterm[Schleife!Schleifenkopf]{Schleifenkopf} und dem \codeterm[Schleife!Schleifenk{\"o}rper]{Schleifenk\"orper}. Der Kopf regelt, wie h\"aufig der Code im K\"orper ausgef\"uhrt wird. Der Schleifenkopf beginnt mit dem Schl\"usselwort \code{for} auf welches folgend die \codeterm{Laufvariable} definiert wird. In \matlab ``l\"auft''/iteriert eine for-Schleife immer(!) \"uber einen Vektor. Die \codeterm{Laufvariable} nimmt mit jeder Iteration einen Wert dieses Vektors an. Im Schleifenk\"orper k\"onnen beliebige Anweisungen ausgef\"uhrt werden. Die Schleife wird durch das Schl\"usselwort \code{end} beendet. Listing \ref{looplisting} zeigt das Grundger\"ust einer for-Schleife. \begin{lstlisting}[caption={Beispiel einer \varcode{for}-Schleife.}, label=looplisting] >> for x = 1:3 x end % die Laufvariable x nimmt mit jeder Iteration der Schleife % einen Wert des Vektors 1:3 an: 1 2 3 \end{lstlisting} \begin{exercise}{facultyLoop.m}{facultyLoop.out} Wie k\"onnte Fakult\"at mit einer Schleife implementiert werden? Implementiere eine \code{for} Schleife, die die Fakul\"at von einer Zahl \varcode{n} berechnet. \end{exercise} \subsubsection{Die \varcode{while} -- Schleife} Eine weiterer Schleifentyp, der weniger h\"aufig eingesetzt wird, ist die \code{while}-Schleife. Auch sie hat ihre Entsprechungen in fast allen Programmiersprachen. \"Ahnlich zur \code{for} Schleife wird auch hier der in der Schleife definierte Programmcode iterativ ausgef\"uhrt. Der Schleifenkopf beginnt mit dem Schl\"usselwort \code{while} gefolgt von einem booleschen Ausdruck. Solange dieser zu \code{true} ausgewertet werden kann, wird der Code im Schleifenk\"orper ausgef\"uhrt. Die Schleife wird mit dem Schl\"usselwort \code{end} beendet. \begin{lstlisting}[caption={Grundstruktur einer \varcode{while} Schleife.}, label=whileloop] while x == true % fuehre diesen sinnvollen Code aus ... end \end{lstlisting} \begin{exercise}{facultyWhileLoop.m}{} Implementiere die Fakult\"at mit einer \code{while}-Schleife. \end{exercise} \begin{exercise}{neverendingWhile.m}{} Implementiere eine \code{while}-Schleife, die unendlich l\"auft. Tipp: wenn der boolesche Ausdruck hinter dem \code{while} zu wahr ausgewertet wird, wird die Schleife weiter ausgef\"uhrt. Das Programm kann mit \keycode{Ctrl+C} abgebrochen werden. \end{exercise} \subsubsection{Vergleich \varcode{for} -- und \varcode{while}--Schleife} \begin{itemize} \item Beide f\"uhren den Code im Schleifenk\"orper iterativ aus. \item Der K\"orper einer \code{for} Schleife wird mindestens 1 mal betreten (au{\ss}er wenn der Vektor im Schleifenkopf leer ist). \item Der K\"orper einer \code{while} Schleife wird nur dann betreten, wenn die Bedingung im Kopf \code{true} ist. \\$\rightarrow$ auch ``Oben-abweisende'' Schleife genannt. \item Die \code{for} Schleife eignet sich f\"ur F\"alle in denen f\"ur jedes Element eines Vektors der Code ausgef\"uhrt werden soll. \item Die \code{while} Schleife ist immer dann gut, wenn nicht klar ist wie h\"aufig etwas ausgef\"uhrt werden soll. Sie ist speichereffizienter. \item Jedes Problem kann mit beiden Typen gel\"ost werden. \end{itemize} \subsection{Bedingte Anweisungen und Verzweigungen} Bedingte Anweisungen und Verzweigungen sind Kontrollstrukturen, die regeln, dass der in ihnen eingeschlossene Programmcode nur unter bestimmten Bedingungen ausgef\"uhrt wird. \subsubsection{Die \varcode{if} -- Anweisung} Am h\"aufigsten genutzter Vertreter ist die \code{if} - Anweisung. Sie wird genutzt um Programmcode nur unter bestimmten Bedingungen auszuf\"uhren. Der Kopf der \code{if} - Anweisung beginnt mit dem Schl\"usselwort \code{if} welches von einem booleschen Ausdruck gefolgt wird. Wenn dieser zu \code{true} ausgewertet werden kann, wird der Code im K\"orper der Anweisung ausgef\"uhrt. Optional k\"onnen weitere Bedingungen mit dem Schl\"usselwort \code{elseif} folgen. Ebenfalls optional ist die Verwendung eines finalen \code{else} - Falls. Dieser wird immer dann ausgef\"uhrt wenn alle vorherigen Bedingungen nicht erf\"ullt wurden. Die \code{if} - Anweisung wird mit \code{end} beendet. Listing \ref{ifelselisting} zeigt den Aufbau einer \code{if} - Anweisung. \begin{lstlisting}[label=ifelselisting, caption={Grundger\"ust einer \varcode{if} Anweisung.}] if x < y % fuehre diesen code aus wenn x < y elseif x > y % etwas anderes soll getan werden fuer x > y else % wenn x == y, wieder etwas anderes end \end{lstlisting} \begin{exercise}{ifelse.m}{} Ziehe eine Zufallszahl und \"uberpr\"ufe mit einer geeigneten \code{if} Anweisung, ob sie \begin{enumerate} \item kleiner als 0.5 ist. \item kleiner oder gr\"o{\ss}er-gleich 0.5 ist. \item (i) kleiner als 0.5, (ii) gr\"o{\ss}er oder gleich 0.5 aber kleiner als 0.75 oder (iii) gr\"o{\ss}er oder gleich 0.75 ist. \end{enumerate} \end{exercise} \subsubsection{Die \varcode{switch} -- Verzweigung} Die \code{switch} Verzweigung wird eingesetzt wenn mehrere F\"alle auftreten k\"onnen, die einer unterschiedlichen Behandlung bed\"urfen. Sie wird mit dem Schl\"usselwort \code{switch} begonnen, gefolgt von der \codeterm{switch Anweisung} (Zahl oder String). Jeder Fall, auf den diese Anweisung \"uberpr\"uft werden soll, wird mit dem Schl\"usselwort \code{case} eingeleitet. Dieses wird gefolgt von der \codeterm{case Anweisung}, die definiert gegen welchen Fall auf Gleichheit getestet wird. F\"ur jeden Fall wird der Programmcode angegeben, der ausgef\"uhrt werden soll. Optional k\"onnen mit dem Schl\"usselwort \code{otherwise} alle nicht explizit genannten F\"alle behandelt werden. Die \code{switch} Anweisung wird mit \code{end} beendet (z.B. in Listing \ref{switchlisting}). \begin{lstlisting}[label=switchlisting, caption={Grundger\"ust einer \varcode{switch} Anweisung.}] mynumber = input('Enter a number:'); switch mynumber case -1 disp('negative one'); case 1 disp('positive one'); otherwise disp('something else'); end \end{lstlisting} Wichtig ist hier, dass in jedem \code{case} auf Gleichheit der switch-Anweisung und der case-Anweisung getestet wird. \subsubsection{Vergleich \varcode{if} -- Anweisung und \varcode{switch} -- Verzweigung} \begin{itemize} \item Mit der \code{if} Anweisung k\"onnen beliebige F\"alle unterschieden und entsprechender Code ausgef\"uhrt werden. \item Die \code{switch} Anweisung leistet \"ahnliches allerdings wird in jedem Fall auf Gleichheit getestet. \item Die \code{switch} Anweisung ist etwas kompakter, wenn viele F\"alle behandelt werden m\"ussen. \item Die \code{switch} Anweisung wird deutlich seltener benutzt und 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 \code{break} und \code{continue} eingesetzt (Listings \ref{continuelisting} und \ref{continuelisting} zeigen, wie sie eingesetzt werden k\"onnen). \begin{lstlisting}[caption={Abbrechen von Schleifen mit \varcode{break}.}, label=breaklisting] >> x = 1; while true if (x > 3) break; end disp(x); x = x + 1; end % output: 1 2 3 \end{lstlisting} \begin{lstlisting}[caption={\"Uberspringen von Code-Abschnitten in Schleifen mit \varcode{continue}.}, label=continuelisting] for x = 1:5 if(x > 2 & x < 5) continue; end disp(x); end % output: 1 2 5 \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 Elemente 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?} 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\"ur Zeile von oben nach unten ausgef\"uhrt. \matlab{} kennt drei Arten von Programmen: \begin{enumerate} \item \codeterm[Skript]{Skripte} \item \codeterm[Funktion]{Funktionen} \item \codeterm[Objekt]{Objekte} (werden wir hier nicht behandeln) \end{enumerate} Alle Programme werden in den sogenannten \codeterm{m-files} gespeichert (z.B. \file{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 erzeugt wurde im \codeterm{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 \codeterm[Funktion]{Funktionen}. \subsection{Funktionen} Eine Funktion in \matlab{} wird \"ahnlich zu einer mathematischen Funktion definiert: \[ y = f(x) \] Die Funktion hat einen Namen $f$, sie \"uber das Argument $x$ einen Input und liefert ein Ergebnis in $y$ zur\"uck. Listing \ref{functiondefinitionlisting} zeigt wie das in \matlab{} umgesetzt wird. \begin{lstlisting}[caption={Funktionsdefinition in \matlab{}}, label=functiondefinitionlisting] function [y] = functionName(arg_1, arg_2) % ^ ^ ^ % Rueckgabewert Argument_1, Argument_2 \end{lstlisting} Ein Funktion beginnt mit dem Schl\"usselwort \code{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 %XXX es ist vielleicht optional, aber gute stil ware es immer hinzuschreiben, oder? mit einem \code{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 \emph{nicht} sichtbar. \item Variablen, die in der Funktion definiert werden erscheinen \emph{nicht} im Workspace. \end{itemize} \item Erh\"oht 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={Ein schlechtes Beispiel einer Funktion, die eine Reihe Sinusse plottet.},label=badsinewavelisting] function meineErsteFunktion() % 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 \end{lstlisting} Das obige 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 geeignet. \item Was sie tut, ist festgelegt und kann von au{\ss}en nicht beeinflusst oder bestimmt werden. \item Sie tut drei Dinge auf einmal: Sinus berechnen \emph{und} Amplituden \"andern \emph{und} graphisch darstellen. \item Es ist nicht (einfach) m\"oglich an die berechneten Daten zu kommen. \item Keinerlei Dokumentation. Man muss den Code lesen und rekonstruieren, was sie tut. \end{itemize} Bevor wir anfangen die Funktion zu verbessern mu{\ss} definiert werden was das zu l\"osende Problem ist: \begin{enumerate} \item Welches Problem soll gel\"ost werden? \item Aufteilen in Teilprobleme. \item Gute Namen finden. \item Definieren der Schnittstellen --- Was m\"ussen die beteiligten Funktionen wissen? Was sollen sie zur\"uckliefern? \item Daten zur\"uck geben (R\"uckgabewerte definieren). \end{enumerate} Das Beispielproblem aus Listing \ref{badsinewavelisting} kann in drei Teilprobleme aufgetrennt werden. (i) Berechnen der \emph{einzelnen} Sinusse. (ii) Plotten der jeweils berechneten Daten und (iii) Koordination von Berechnung und Darstellung mit unterschiedlichen Amplituden. \paragraph{I. Berechnung eines einzelnen Sinus} Die Berechnung eines einzelnen Sinus ist ein typischer Fall f\"ur eine Funktion. Wiederum macht man sich klar, (i) wie die Funktion hei{\ss}en soll, (ii) welche Information sie ben\"otigt und (iii) welche Daten sie zur\"uckliefern soll. \begin{enumerate} \item \codeterm[Funktion!Name]{Name}: der Name sollte beschreiben, was die Funktion tut. In diesem Fall berechnet sie einen Sinus. Ein geeigneter, kurzer Name w\"are also \code{sinewave()}. \item \codeterm[Funktion!Argumente]{Argumente}: die zu brechnende Sinusschwingung sei durch ihre Frequenz und die Amplitude bestimmt. Des Weiteren soll noch festgelegt werden, wie lang der Sinus sein soll und mit welcher zeitlichen Aufl\"osung gerechnet werden soll. Es werden also vier Argumente ben\"otigt, sie k\"onnten hei{\ss}en: \varcode{amplitude}, \varcode{frequency}, \varcode{t\_max}, \varcode{t\_step}. \item \codeterm[Funktion!R{\"u}ckgabewerte]{R\"uckgabewerte}: Um den Sinus korrekt darstellen zu k\"onnen brauchen wir die Zeitachse und die entsprechenden Werte. Es werden also zwei Variablen zur\"uckgegeben: \varcode{time}, \varcode{sine} \end{enumerate} Mit dieser Information ist es nun gut m\"oglich die Funktion zu implementieren (Listing \ref{sinefunctionlisting}). \begin{lstlisting}[caption={Funktion zur Berechnung eines Sinus.}, label=sinefunctionlisting] function [time, sine] = sinewave(frequency, amplitude, t_max, t_step) % Calculate a sinewave of a given frequency, amplitude, % duration and temporal resolution. % % [time, sine] = sinewave(frequency, amplitude, t_max, t_step) % % Arguments: % frequency: the frequency of the sine % amplitude: the amplitude of the sine % t_max : the duration of the sine in seconds % t_step : the temporal resolution in seconds % Returns: % time: vector of the time axis % sine: vector of the calculated sinewave time = (0:t_step:t_max); sine = sin(frequency .* time .* 2 * pi) .* amplitude; end \end{lstlisting} \paragraph{II. Plotten einer einzelnen Schwingung} Das Plotten der berechneten Sinuschwingung kann auch von einer Funktion \"ubernommen werden. Diese Funktion hat keine andere Aufgabe, als die Daten zu plotten. Ihr Name sollte sich an dieser Aufgabe orientieren (z.B. \code{plotFunction()}). Um einen einzelnen Sinus zu plotten werden im Wesentlichen die x-Werte und die zugeh\"origen y-Werte ben\"otigt. Da mehrere Sinus geplottet werden sollen ist es auch sinnvoll eine Zeichenkette f\"ur die Legende an die Funktion zu \"ubergeben. Da diese Funktion keine Berechnung durchf\"uhrt wird kein R\"uckgabewert ben\"otigt (Listing \ref{sineplotfunctionlisting}). \begin{lstlisting}[caption={Funktion zur graphischen Darstellung der Daten.}, label=sineplotfunctionlisting] function plotFunction(x_data, y_data, name) % Plots x-data against y-data and sets the display name. % % plotFunction(x_data, y_data, name) % % Arguments: % x_data: vector of the x-data % y_data: vector of the y-data % name : the displayname plot(x_data, y_data, 'displayname', name) end \end{lstlisting} \paragraph{III. Erstellen eines Skriptes zur Koordinierung} Die letzte Aufgabe ist die Koordinierung der Berechung und des Plottens f\"ur mehrere Amplituden. Das ist die klassische Aufgabe f\"ur ein \codeterm{Skript}. Auch hier gilt es einen ausdrucksvollen Name zu finden. Da es keine Argumente und R\"uckgabewerte gibt, m\"ussen die ben\"otigten Informationen direkt in dem Skript defniniert werden. Es werden ben\"otigt: ein Vektor f\"ur die Amplituden, je eine Variable f\"ur die gew\"unschte Frequenz, die maximale Zeit auf der x-Achse und die zeitliche Aufl\"osung. Das Skript \"offnet schlie{\ss}lich noch eine neue Abbildung mit \code{figure()} und setzt das \code{hold on} da nur das Skript wei{\ss}, das mehr als ein Plot erzeugt werden soll. Das Skript ist in Listing \ref{sinesskriptlisting} dargestellt. \begin{lstlisting}[caption={Kontrollskript zur Koordination von Berechnung und graphischer Darstellung.},label=sinesskriptlisting] amplitudes = 0.25:0.25:1.25; frequency = 2.0; t_max = 10.0; t_step = 0.01; figure() hold on for i = 1:length(amplitudes) [x_data, y_data] = sinewave(frequency, amplitudes(i), ... t_max, t_step); plotFunction(x_data, y_data, sprintf('freq: %5.2f, ampl: %5.2f',... frequency, amplitudes(i))) end hold off legend('show') \end{lstlisting} \begin{exercise}{plotMultipleSinewaves.m}{} Erweiter das Programm so, dass die Sinusse f\"ur einen Satz von Frequenzen geplottet wird. \pagebreak[4] \end{exercise} \subsection{Einsatz von Funktionen und Skripten} Funktionen sind kleine Codefragmente, die im Idealfall genau eine Aufgabe erledigen. Sie besitzen einen eigenen \determ{G\"ultigkeitsbereich}, das hei{\ss}t, dass Variablen aus dem globalen Workspace nicht verf\"ugbar sind und Variablen, die lokal in der Funktion erstellt werden nicht im globalen Workspace sichtbar werden. Dies hat zur Folge, dass Funktionen all die Informationen, die sie ben\"otigen, von au{\ss}en erhalten m\"ussen. Sie nehmen \determ{Argumente} entgegen und k\"onnen \determ{R\"uckgabwerte} zur\"uckliefern. Die Verwendung von Funktionen ist der Verwendung von Skripten fast immer vorzuziehen sind. Das hei{\ss}t aber nicht, das Skripte zu verteufeln w\"aren und und vermieden werden sollten. In Wahrheit sind beide daf\"ur gemacht, Hand in Hand ein Problem zu l\"osen. W\"ahrend die Funktionen relativ kleine ``verdauliche'' Teilprobleme l\"osen, werden Skripte eingesetzt um den Rahmen zu bilden und den Ablauf zu koordinieren (Abbildung \ref{programlayoutfig}). \begin{figure} \includegraphics[width=0.5\columnwidth]{simple_program.pdf} \titlecaption{Ein typisches Programmlayout.}{Das Kontrollskript koordiniert den Aufruf der Funktionen, \"ubergibt Argumente und nimmt R\"uckgabewerte entgegen.}\label{programlayoutfig} \end{figure}