GNU Octave
kurs elementarny

Podstawowe rodzaje zmiennych

Octave rzadko kiedy bywa używany jak zwykły kalkulator do wyznaczania wartości gotowych wyrażeń matematycznych. Jego prawdziwa siła objawia się bowiem dopiero wtedy, gdy potraktujemy go jak język programowania, w którym przygotowuje się wielolinijkowe skrypty. Takie skrypty z reguły zawierają zmienne i funkcje definiowane przez użytkownika.

Zmienne

Definiowanie zmiennych jest banalnie proste: piszemy jej nazwę, znak =, a po nim wartość zmiennej, np.:

> a = 1
a = 1

Dużo ciekawsza jest kwestia rodzaju zmiennych, jakich możemy używać w Octave. W niniejszym kursie skoncentrujemy się na najbardziej użytecznych typach danych:

who -l variables
Skalary
Skalary są to liczby, np. 123, -3.14, 1.2e-10. Niezależnie od zapisu, skalary reprezentowane są przez Octave jako tzw. liczby zmiennopozycyjne podwójnej precyzji (IEEE-754 double).

Uwaga: Octave umożliwia też deklarowanie skalarów innych typów, np. całkowitych (8, 16, 32 i 64 bitowych), zmiennopozycyjnych w pojedynczej precyzji oraz zespolonych. Przykłady skalarów zespolonych: i, 1 + 3i, 1.2 - 3.4i.

Wektory
Wektory są to ciągi skalarów. Definiujemy je, podając wartości elementów oddzielone przecinkami, np.:
> a = [1, 2, 3, 4]
a =
   1   2   3   4
Uwaga: przecinki można pominąć, ale może prowadzić to do subtelnych błędów podczas interpretacji wyrażeń.

Dostęp do wartości n-ego elementu wektora a zapewnia wyrażenie a(n):

> a(2)=3
a =  
   1   3   3   4
Jak widać, pierwszy element wektora n-elementowego to a(1), a element ostatni to a(n).

Wektory można łatwo rozszerzać o nowe elementy:

> a = [a, 7, [10,100]]
a =
     1     3     3     4     7    10   100
Liczbę elementów wektora można zbadać funkcją length
> length(a)
ans =  7
W powyższych przykładach mieliśmy do czynienia z tzw. wektorami wierszowymi. Octave rozpoznaje też wektory kolumnowe. Kolejne elementy wektorów kolumnach oddziela się od siebie średnikami:
> v = [1; 2; 5]
v =
   1
   2
   5
Macierze
Elementami wektorów kolumnowych mogą być nie tylko liczby, ale i wektory wierszowe. Oto przykład definicji m jako wektora kolumnowego o dwóch elementach, z których każdy jest dwuelementowym wektorem wierszowym:
> m = [[1, 2]; [3, 4]]
m =
   1   2
   3   4

Takie uogólnione wektory nazywamy macierzami.

Macierz o n wierszach i m kolumnach zwie się "macierzą n na m". Jeżeli m = n, macierz zwie się kwadratową. W powyższym przykładzie m jest więc macierzą kwadratową o dwóch wierszach i dwóch kolumnach, czyli "2 na 2".

Macierze można też interpretować jako wektory wierszowe, których elementy są wektorami kolumnowymi:

m = [[1; 3], [2; 4]]
m =
   1   2
   3   4
Zapis macierzy zwykle upraszcza się jeszcze bardziej, po prostu podając wartości elementów w kolejnych wierszach i kolumnach:
m = [1, 2; 3, 4]
m =
   1   2
   3   4
Liczbę wierszy dowolnej macierzy zwraca funkcja rows, liczbę kolumn zwraca funkcja columns, a funkcja size zwraca liczbę wierszy i kolumn jako wektor "1 na 2":

> rows(m)
ans =  2
> columns(m)
ans =  2
> size(m)
ans =
   2   2

Uwaga! Dla Octave skalary i wektory to pewne specjalne rodzaje macierzy: skalary to macierze "1 na 1", wektory wierszowe to macierze "1 na n", a wektory kolumnowe to macierze "n na 1".

Aby uzyskać dostęp do elementu leżącego w w-tym wierszu i k-tej kolumnie macierzy m, piszemy m(w,k):

> m(1,2)
ans =  2

Zakresy
Zakresy to specjalne typy danych ułatwiające zapis i operacje na wektorach, których elementy tworzą ciąg arytmetyczny. Definicje zakresów zawierają wartość pierwszego elementu ciągu, opcjonalnie – wartość różnicy między jego dwoma kolejnymi wyrazami oraz wartość maksymalną, której elementy ciągu nie mogą przekroczyć. Wartości te oddziela się od siebie dwukropkami, przy czym jeżeli pominie się środkową liczbę, Octave założy, że jej wartość wynosi 1. Dlatego wyrażenie
> 1:4
definiuje zakres odpowiadający ciągowi [1, 2, 3, 4]. Analogicznie
> 1 : 0.5 : 4.1
odpowiada wektorowi [1, 1.5, 2, 2.5, 3, 3.5, 4].

Zakresy nie tylko upraszczają zapis, ale przede wszystkim umożliwiają optymalizację działania programu. Np. jeżeli zdefiniujemy zmienną a wyrażeniem

> a = 1:100000
to Octave zarezerwuje dla tej zmiennej zaledwie 24 bajty (3 liczby zmiennopozycyjne). Równoważny tej zmiennej wektor musiałby mieć 100 000 elementów i zajmowałby w pamięci operacyjnej aż 800 000 bajtów.
Napisy
Napisy to ciągi liter ujętych w znaki cudzysłowu (lub apostrofy):
> a = "ala ma kota"
a = ala ma kota

Transpozycja macierzy

Transpozycja macierzy to zamiana jej kolumn na wiersze i wierszy na kolumny. W Octave transpozycję macierzy wykonuje się za pomocą specjalnego operatora ' (apostrof). Oto prosty przykład:

> m = [1, 2, 3; 4, 5, 6]
m =
   1   2   3
   4   5   6
> b = m'
b =
   1   4
   2   5
   3   6

W powyższym przykładzie b jest macierzą transponowaną do m, tj. b czytana kolumnami wygląda tak samo, jak m czytana wierszami.

Jednym z najważniejszym zastosowaniem transpozycji jest zamiana wektorów wierszowych na kolumnowe, wektorów kolumnowych na wierszowe i definiowanie „zakresów kolumnowych”. Tę ostatnią cechę ilustruje następujący przykład :

> v = [1:4]'
v =
   1
   2
   3
   4

Uwaga: Jeżeli macierz m ma elementy zespolone, to wyrażenie m' oznacza sprzężenie hermitowskie m. Transpozycję macierzy zespolonej oznacza się operatorem .' (kropka apostrof), np.

m = v.'

Dla macierzy rzeczywistych oba zapisy (z kropką lub bez) są równoważne.

Zapisywanie i odczytywanie zmiennych z pliku

W przypadku bardziej zaawansowanych obliczeń niezwykle ważna jest umiejętność zapisywania i wczytywania danych z plików. Szczególnie istotne jest zapisywanie końcowych wyników żmudnych obliczeń i wyników obliczeń pośrednich, które być może zechcemy kontynuować w przyszłości.

Aby zapisać dowolną zmienną, np. wektor a = [1,2,3,4,100], posługujemy się poleceniem save:

> save "a.mat" a

Pierwszym argumentem tego polecenia jest zwykle nazwa pliku (tu: a.txt). Następnie podajemy wykaz zmiennych, które chcemy w tym pliku zapisać (tu: jedna zmienna a). Oto przykład instrukcji zapisującej 3 zmienne, a, x i m:

> save "axm.txt" a x m

Jeżeli nie podamy żadnych zmiennych, Octave zapisze w pliku wszystkie zdefiniowane aktualnie zmienne.

> save "sesja.txt"

Aby odczytać tak zapisane zmienne, stosujemy polecenie load:

> load "axm.txt"

Warto zwrócić uwagę na to, że funkcja load nie tylko wczytuje wartości zmiennych, ale też nadaje im zapisane w piku nazwy.

Po wczytaniu zmiennych z pliku warto wydać polecenie who -l variables

> who -l -variables

które wyświetla podstawowe informacje o wszystkich zdefiniowanych aktualnie zmiennych.

Obie funkcje, save i load, posiadają mnóstwo dodatkowych opcji i potrafią obsługiwać dane w wielu formatach, w tym w formatach binarnych programu Matlab.

Quiz

  1. Czym różnią się w Octave następujące zmienne:
    > a = 1
    > b = 1.0
    > c = 1e0
    
    
  2. Jak w Octave zapisuje się wektory wierszowe?
  3. Jak w Octave zapisuje się wektory kolumnowe?
  4. Czym różnią się następujące zmienne:
    > a = [1 2 3];
    > b = [1, 2, 3];
    > c = [1; 2; 3];
    
  5. Jaki jest związek skalarów, wektorów wierszowych i wektorów kolumnowych z macierzami?
  6. Co to są zakresy? Czym różnią się od wektorów?
  7. Co to jest transpozycja macierzy? Jak oznacza się ja w Octave?
  8. W jaki sposób można łatwo zamienić wektor kolumnowy w wierszowy?
  9. W jaki sposób zapisuje się zmienne Octave w zewnętrznych plikach?
  10. W jaki sposób odczytuje się zmienne Octave z plików?

Zadania

  1. Utwórz wektor v o elementach 1, 2, 5, 10 i zapisz go w pliku v.mat.
  2. Po wykonaniu poprzedniego zadania zamknij program, otwórz go ponownie i wczytaj zmienną z pliku v.mat. Sprawdź, że w programie z powrotem pojawiła się zmienna v.
  3. Dla zmiennej v z poprzedniego punktu sprawdź, jak Octave interpretuje wyrażenia
    > v + v
    > v + 1
    > v * 2
    > v'
    
  4. W pliku "x.h5" znajduje się definicja wektora x zapisana w binarnym formacie hdf5.
    • Wczytaj ten plik.
    • Sprawdź, że w programie pojawiła się zmienna x (who -l variables).
    • Sprawdź, ile wierszy i kolumn ma x (funkcjami rows, columns).
    • Wyznacz najmniejszą, największą i średnią wartość elementów x (funkcjami min, max, mean).