In der letzten Ausgabe haben wir euch bereits mit einigen der Eigenheiten und der „Denkweise“ von Matlab vertraut gemacht und gezeigt, wie ihr sie zu eurem Vorteil nutzen könnt. Durch die matrix- und vektororientierte Arbeitsweise Matlabs lassen sich elementare Rechnungen schnell auf ganzen Matrizen durchführen – weit schneller als sie elementweise mittels for-Schleifen-Konstrukten durchzugehen. In diesem Artikel soll ein weiterer Aspekt des „Vektordenkens“ vorgestellt werden: der Datentyp Boolean und wie er genutzt werden kann.

Mit ein paar kleinen Tricks sieht Matlab das "Busy"-Feld nicht mehr ganz so lange.

Mit ein paar kleinen Tricks sieht Matlab das “Busy”-Feld nicht mehr ganz so lange.[media-credit id=51 align="aligncenter" width="640"]

Dieser Datentyp ist nach dem englischen Mathematiker und Logiker George Boole benannt und beschreibt eine logische Variable. Sie kann die Werte „wahr“ oder falsch“ annehmen; in Matlab entsprechend 1 oder 0. Soweit wahrscheinlich schon von anderen Programmiersprachen oder diversen Vorlesungen bekannt.

Doch in Matlab hat sie viel Nutzen. Ebenso wie Zahlen können auch Booleans in Form von Matrizen und Vektoren strukturiert werden. Weiter können sie mit Zahlen direkt verrechnet werden. In diesem Falle werden sie wie die „normalen“ Zahlen 0 und 1 behandelt.

Zunächst sollen hier einmal kurz die grundlegenden Operatoren vorgestellt werden, die mit Booleans arbeiten. Dabei unterscheidet man zwischen relationalen und logischen Operatoren.

Relationale Operatoren sind, wie der Name verrät, vergleichende Operatoren: <, <=, >, >=, ==, und ~=. Sie vergleichen zwei Objekte (im Normalfall Zahlen oder Matrizen) und geben das Ergebnis als Boolean aus. So ergibt 3==2 den Wert 0 und [1 2 3]<=2 den Boolean-Vektor [1 1 0]. Wieder können diese elementweise verwendet werden: [1 2 3]>=[3 2 1] ergibt [0 1 1].

Logische Operatoren akzeptieren üblicherweise Booleans als Eingabe und geben wiederum Booleans aus. Sie akzeptieren in Matlab auch gewöhnliche Zahlen, hierbei wird jedoch jeder Eintrag, welcher nicht 0 ist, wie 1 behandelt. Die logischen Operatoren, die Matlab kennt sind UND (&, &&), ODER (|,||), NICHT (~) und XOR (xor(A,B)) und folgen den bekannten Wertetabellen. Sie sind wieder elementweise einsetzbar. Die „doppelten“ Operatoren && und || sind besondere Varianten: Sie sind sogenannte „Short-circuit“-Operatoren und werten bei Eingabe A&&B bzw. A||B die Werte von B gar nicht mehr aus, wenn durch A das Ergebnis bereits feststeht. So ist, wenn A falsch ist auch immer A UND B falsch, ist A wahr, ist auch immer A ODER B wahr. Sie bieten damit eine Steigerung der Effizienz.

Eine praktische Anwendung für Booleans, relationale und logische Operatoren liegt in der Adressierung von Elementen einer Matrix. Matlab akzeptiert nicht nur die bekannte Angabe einzelner oder mehrerer Zeilen und Spalten zur Adressierung von Elementen, sondern auch Booleans: Dabei muss die Boolean Matrix dieselbe Anzahl Elemente wie die abzufragende Matrix haben. Matlab listet dann sämtliche Elemente in einem Spaltenvektor auf, an deren Position die Boolean-Matrix wahr ist.

Ist beispielsweise A=[1 2 3;4 5 6] und B die Boolean-Matrix [0 1 0; 1 1 1] ergibt die Anfrage C=A(B) die Matrix C=[4;2;5;6]. Die Reihenfolge ergibt sich daraus, dass Matlab B intern vektorisiert, also alle Spalten von B untereinander als Spaltenvektor schreibt. Dadurch, dass die Booleans auch als Zahlen funktionieren, funktioniert dieser Trick: D=A.*B. Das ergibt die einfache Möglichkeit, eine Matrix D zu konstruieren, die dieselbe Größe wie A behält und an allen „wahren“ Stellen von B die ursprünglichen Werte, aber an all den Stellen, in denen B „falsch“ ist nur noch eine 0 steht. Statt direkt Boolean-Matrizen zu verwenden, ist es oft praktisch gleich logische Abfragen zu verwenden. A(A>0) liefert zum Beispiel direkt alle positiven Einträge der Matrix A, B(B>=0 & B<=1) liefert alle Elemente von B, die zwischen null und eins liegen.

Durch die Verwendung solcher Konstrukte lassen sich einige relativ ineffiziente if-Abfragen einfach ersetzen. Insbesondere in dem folgenden, häufig auftretenden Fall lässt sich viel Rechenzeit sparen: Wir haben eine Matrix voller Werte. Abhängig von diesen Werten sollen irgendwelche Rechnungen mit selbigen angestellt werden. Als Beispiel wollen wir Werte gewichten. Ist der Wert negativ, so soll er verdoppelt werden, ist er positiv halbiert. Ein einfacher Ansatz wäre:

for i=1:size(A(:))

if A(i)<0

A(i)=2*A(i);

elseif A(i)>0

A(i)=0.5*A(i);

end;

end;

Ein Testlauf mit einer Zufallsmatrix A mit 10000 Werten ergab eine Rechenzeit von 165.35 Sekunden – knapp 2.5 Minuten für eine per se simple Aufgabe. Versuchen wir jetzt, das Ganze mithilfe von Booleans darzustellen. Die einzelnen if-Abfragen lassen sich über A<0 bzw. A>0 matrixwertig realisieren. Alle negativen Einträge lassen sich durch A.*(A<0) bestimmen, alle positiven durch A.*(A>0). Zusammen mit den Multiplikationen ergibt sich folgender Einzeiler:

A=2*A.*(A<0)+0.5*A.*(A>0);

Oder noch kürzer:

A=(2*(A<0)+0.5*(A>0)).*A;

Die Rechenzeit liegt bei 2.8 bzw. 2.38 Sekunden. Das sind nur 1.69 beziehungsweise 1.44 Prozent der Rechenzeit des ersten Versuches – also ein erheblicher Zeitgewinn. So lässt sich durch eine kleine Veränderung des Programmes die Effizienz massiv verbessern. Das hilft nicht nur bei fortgeschrittenen Programmen, sondern sorgt auch so manches Mal bei euren Korrekteuren für großzügigere Bepunktung, wenn die Programme schneller laufen.

In der nächsten Ausgabe gibt es weitere Tipps um eure Matlab-Programme zu verbessern. Teil 1 findet ihr hier.

Noch keine Kommentare, sei der Erste!