Wykład 4 Matlab cz.3 Tablice i operacje na tablicach Dr inż. Zb. Rudnicki Tematyka wykładu 1. Macierze, wektory, tablice - wprowadzenie 2. Rozmiary i typy tablic 3. Zapis - nawiasy i znaki specjalne 4. Przydział pamięci dla tablic - deklarowanie 5. Sposoby wprowadzania i generowania tablic 6. Działania wektorowe - bez pętli 7. Wczytywanie tablicy z pliku 8. Działania na macierzach 9. Rozwiązywanie układów równań liniowych 10. Znajdowanie pierwiastków wielomianu 2 1
1. Tablice jedno i wielowymiarowe Tablica to zbiór elementów jednakowego typu, identyfikowanych przez wspólną nazwę oraz indywidualne numery zwane indeksami W Matlabie indeksy zapisuje się po nazwie tablicy w nawiasach okrągłych, oddzielając przecinkami np.: TAB1(4, 6) Nazwa bez indeksów np.: TAB1 - reprezentuje całą tablicę. Należy rozróżnić pojęcia liczba wymiarów oraz rozmiary tablicy Liczba wymiarów tablicy - to liczba indeksów określających jej pojedynczy element, na przykład: Bt(5), W(j), Sila(j+1) - to elementy tablic jednowymiarowych czyli wektorów; HH(3, 5), Masy(j, k) - to elementy tablic dwuwymiarowych czyli macierzy; ZET(3, 5, 7), Mom(j, k, l), T(j-1,3,1) - to elementy tablic trójwymiarowych. Rozmiary tablicy - określone są maksymalnymi wartościami indeksów i wyznaczają liczbę wszystkich elementów. 3 Tablica jednowymiarowa czyli wektor - domyślnie: kolumnowy, element ma jeden indeks: nr_wiersza Liczba wymiarów tablic Tablica dwuwymiarowa czyli macierz (ciąg wektorów kolumnowych) - element ma dwa indeksy: nr_wiersza, nr_kolumny Tablica trójwymiarowa - element ma trzy indeksy: nr_wiersza, nr_kolumny, nr_strony Można też stosować tablice o większej liczbie wymiarów (kolejne indeksy dopisywane z prawej) 4 2
Tablice czy macierze W Matlabie istnieją tablice (ang.: arrays) jedno i wielowymiarowe. Tablice w Matlabie bywają czasem określane jako macierze (ang.: matrix) - chociaż w matematyce macierzami nazywa się tylko tablice dwuwymiarowe a wektorami tablice jednowymiarowe - wynika to stąd, że Matlab opracowywany był głównie dla macierzy (matrix), i od tego pochodzi jego nazwa: Matlab = MATrix LABoratory - a potem dopiero wprowadzono tablice (arrays) o większej liczbie wymiarów. Domyślnie, tablice mają elementy typu double - liczby rzeczywiste podwójnej precyzji. Typ double musi być użyty jeśli stosowane są obliczenia 5 2. Rozmiary i typy tablic 6 3
2.1. Rozmiary tablic. Funkcja SIZE Liczbę wymiarów i rozmiary nieznanej tablicy można sprawdzić funkcją size(macierz) Skalar to macierz o rozmiarach (1, 1): >> b=2; >> size(b) 1 1 Wektor wierszowy to tablica o tylko jednym wierszu czyli rozmiarach (Lw=1, Lk=n): >> c=[8,2,6,3] c = 8 2 6 3 >> size(c) 1 4 a wektor kolumnowy to tablica o jednej kolumnie czyli rozmiarach (Lw=n, Lk=1): >> d=[4;7;2;1;6]; >> size(d) 5 1 Sprawdźmy czy funkcja size działa dla tablic o większej liczbie wymiarów. Tworzymy tablicę trójwymiarową przez zdefiniowanie ostatnego jej elementu: >> Y(2,4,2)=3.75 Y(:,:,1) = 0 0 0 0 0 0 0 0 Y(:,:,2) = 0 0 0 0 0 0 0 3.7500 >> [Lw,Lk,Ls]=size(Y) Lw = 2 Lk = 4 Ls = 2 Otrzymaliśmy liczbę wierszy Lw, liczbę kolumn Lk i liczbę stron Ls 7 2.2. Typy tablicowe Oprócz zwykłych tablic o elementach typu double istnieją: tablice numeryczne o elementach będących liczbami całkowitymi: int8, int16, uint8, uint16,... tablice znakowe - typu char, macierze rzadkie - typu sparse - w których zapamiętywane są tylko elementy niezerowe, tablice komórkowe - typu cell - w których każdy element może być innego typu (także tablicowego), tablice strukturalne - typu struct - w których wiersze są rekordami złożonymi z pól różnych typów, identyfikowanych nazwami 8 4
Tablica znakowa Elementami tablicy znakowej nie mogą być łańcuchy o różnej długości, na przykład: >> TZ=['wewe','ee','o'; 'f','kk','sss']??? Error using ==> vertcat CAT arguments dimensions are not consistent. Dla takich łańcuchów można użyć opisanej dalej tablicy komórkowej albo usunąć błąd przez wydłużenie niektórych łańcuchów dostawionymi spacjami, tak aby wszystkie łańcuchy miały jednakową długość (po 4 znaki): >> TZ=['wewe', ' ee ', ' o'; ' f', ' kk', ' sss'] TZ = wewe ee o f kk sss 9 Tablica komórkowa Wartości elementów tablicy komórkowej wpisujemy między klamrami {...} W zwykłych tablicach wszystkie elementy muszą być tego samego typu, w tablicy komórkowej każdy element może być innego typu np.: >> TK={3.51, 'ala', 88; 'pp', 12, [3, 4; 9, 1.2] } TK = [3.5100] 'ala' [ 88] 'pp' [ 12] [2x2 double] >> TK(2,3) [2x2 double] Aby uzyskać wartości elementu trzeba indeksy wpisać między klamrami: >> TK{2,3} 3.0000 4.0000 9.0000 1.2000 10 5
3. Zapis - Nawiasy i znaki specjalne 11 3.1. Zapis - Nawiasy prostokątne [ ] Używane są do: definiowania wartości wektorów i macierzy np.: V=[2.5, 3, 12], M=[1, 0, 3; 0.5, 2, 4] elementy wiersza można oddzielać przecinkami lub spacjami: V=[2.5 3 12], M=[1 0 3; 0.5 2 4] sklejania (konkatenacji): - wektorów, - macierzy - łańcuchów znakowych (tekstów) np.: disp([ Sila=, num2str(f1), Moment=, num2str(mg)]) 12 6
3.2. Zapis - Indeksy elementów tablic Indeksy (wskaźniki) należy umieszczać w nawiasach okrągłych np.: V(1), b(16), M(i,j), MACIERZ_A(3, 2) Indeksy mogą być wyrażeniami: sila(2*j+1) MACIERZ_A(w+1, k-2) Indeksy mogą również być ciągami: sila(2:2:8) MACIERZ_A(w:w+5, kp:kk) Dwukropek zamiast indeksu oznacza wszystkie wartości indeksu np.: >> X=[3 7 2; 8 2 5]; >> X(2,:) 8 2 5 13 3.3. Zapis - Rola dwukropka w wybieraniu elementów Dla danej macierzy: >>A= [ 1 2 3 4; 7 8 9 10] A = 1 2 3 4 7 8 9 10 a) wybieramy wszystkie wiersze z drugiej kolumny: >>A(:, 2) 2 8 b) wybieramy kolumnę 2 oraz 3: >>A(:, 2:3) 2 3 8 9 c) wybieramy kolumny od 1 co 2 do 4: A(:, 1:2:4) 1 3 7 9 d) drugi wiersz i wszystkie kolumny : A(2, :) 7 8 9 10 e) zamiana macierzy na wektor (kolumnami): A(:) 1 7 2 8 3 9 4 10 14 7
4. Przydział pamięci dla tablic - deklarowanie W większości języków niezbędne jest deklarowanie typu i wymiarów tablic dla przydzielenia odpowiedniego miejsca w pamięci operacyjnej. W Matlabie przydział pamięci dla tablic odbywa się automatycznie - przez rozpoznanie rodzaju wpisanych wartości oraz maksymalnych wskaźników oraz dynamicznie - to znaczy w trakcie wykonywania programu Tablicę można zadeklarować - wstępnie ustalając wymiary - przez podanie wartości początkowej ostatniego elementu: >> B(2,4)=0 B = 0 0 0 0 0 0 0 0 15 4.1. Dynamiczne zwiększanie rozmiaru tablicy Jeśli potem w programie wystąpią większe wartości wskaźników to macierz zostanie powiększona. Na przykład instrukcja B(3,5)=2 spowoduje powiększenie rozmiarów macierzy B: poprzednio B(2,4) teraz B(3,5) >>B(3,5)= 2 B = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 16 8
5. Sposoby wprowadzania i generowania tablic Tablice mogą powstawać na różne sposoby np. przez: 5.1. wpisanie wszystkich elementów w nawiasach prostokątnych, przy czym elementy wiersza oddzielamy przecinkami lub spacjami a średniki oddzielają poszczególne wiersze: >>A = [ 3.4, 2.7, 1.4; 8.5, 3.5, 6.7] A= 3.4 2.7 1.4 8.5 3.5 6.7 5.2. generowanie na podstawie indeksów - zmienianych w pętlach, 5.3. generowanie na podstawie ciągów indeksów - bez pętli, 5.4. generowanie tablic funkcjami macierzowymi, 5.5. wczytywanie tablic z pliku (i zapis do pliku). 17 Działania - w pętli czy bez pętli? Wektoryzacja działań W tradycyjnych językach programowania (jak Basic, Fortran, Pascal, C,...) operowanie na wektorach wymaga użycia pętli a przy macierzach - podwójnej pętli. Z tego powodu warto poznać metody stosujące pętle. W pętlach wykonuje się działania na elementach tablic a więc działania skalarne. Matlab zaprojektowano jednak do działań wektorowych na całych wektorach i macierzach bez zastosowania pętli. Działania takie mają krótszy zapis i wykonywane są szybciej. Zastępowanie pętli działaniami wektorowymi i macierzowymi nazywa się wektoryzacją 18 9
Generowanie indeksów - bez pętli oraz w pętli Zapisy bardzo podobne lecz skutek inny: Bez pętli generuje się cały ciąg (wektor) wartości indeksu: >> i=1:4; >> i i = 1 2 3 4 % Zastosujmy transpozycję: >> j=(1:3) j = 1 2 3 W pętli indeks jest skalarem i przy każdym obiegu ma jedną konkretną wartość, a po wyjściu z pętli ma wartość końcową: >> for k=1:4; end; >> k k = 4 19 Generowanie wektora wierszowego jako ciągu (bez pętli) a) Wektory, których elementy stanowią postęp arytmetyczny można generować bez pętli podając trzy parametry oddzielone dwukropkami: pierwszy_element : przyrost : ostatni element np.: >> x = -2 : 0.5 : 2 x= -2.0-1.5-1.0-0.5 0.0 0.5 1.0 1.5 2.0 b) Po wygenerowaniu wektora-indeksu jako ciągu, można wykorzystać go do definiowania innych wektorów np.: >> i=1:9; x=(i-5)/2 x= -2.0-1.5-1.0-0.5 0.0 0.5 1.0 1.5 2.0 >> y=(i-5).^2 y = 16 9 4 1 0 1 4 9 16 20 10
Generowanie wektora kolumnowego jako ciągu bez pętli Można wygenerować wektor (ogólnie: tablicę) generując najpierw ciąg wskaźników np. i (gdzie apostrof ['] jest operatorem transponowania): >> i=(1:4)' i = 1 2 3 4 a na jego podstawie wektor np.: X złożony z kolejnych liczb parzystych od 2 do 8: >> X=2*i; X X = 2 4 6 8 Zauważ, że nie generujemy pojedynczych elementów X(i) wektora X, ale cały wektor X 21 Generowanie elementów wektora w pętli W pętlach definiuje się przy każdym obiegu tylko jeden (np. i-ty) element tablicy o określonych indeksach (np.: X(i)) Jeśli elementy tablicy generujemy w pętli to może niepotrzebnie wielokrotnie wystąpić operacja deklarowania coraz większych rozmiarów tablicy (i przydzielania jej nowych komórek pamięci) np.: >> for i=1:4; X(i)=2*i; X, end; X = X = X = X = 2 2 4 2 4 6 2 4 6 8 22 11
Generowanie elementów wektora w pętli (c.d.) Aby nie marnować na to czasu komputera wskazane jest przed generowaniem elementów tablicy zarezerwować dla niej miejsce w pamięci przez wstawienie zera do elementu o maksymalnych wartościach wskaźników np.: >> clear >> B(4)=0, for i=1:4; B(i)=2*i; B, end; B = 0 0 0 0 B = 2 0 0 0 B = 2 4 0 0 B = 2 4 6 0 B = 2 4 6 8 23 Generowanie wektorów Programy w edytorze: Tabela i wykres funkcji sinus Bez pętli wyznaczamy całe wektory X oraz Y i po transpozycji sklejamy je w jedną macierz: clear; clc; % nagłówek tabeli: fprintf('\n x sin(x)\n'); X=0:0.2:2*pi; Y=sin(X); XY=[X',Y']; disp(xy) plot(x,y); grid on; % to wykres i siatka title('funkcja sinus'); % tytuł wykresu xlabel('x'); ylabel('y'); % etykiety osi W pętli FOR wyznaczamy poszczególne (k-te) elementy wektorów X(k), Y(k) clear; clc; k=0; % zerujemy licznik elementów tabeli fprintf('\n x sin(x)'); % nagłówek tab. for x=0:0.2:2*pi k=k+1; X(k)=x; Y(k)=sin(x); fprintf('\n %7.4f %7.4f',X(k),Y(k)); end plot(x,y); grid on; % to wykres i siatka title('funkcja sinus'); % tytuł wykresu xlabel('x'); ylabel( y'); % etykiety osi 24 12
Generowanie macierzy - w podwójnej pętli (1) Przykład 1a. Wygenerować macierz A: 1 5 9 13 3 7 11 15 5 9 13 17 7 11 15 19 % Program 1 clear; for w=1:4 el=2*w-1; for k=1:4 A(w,k)=el; el=el+4; end end A, % wyświetli macierz W pętlach otrzymujemy kolejne numery wierszy w oraz kolumn k. Na podstawie w ustalany jest pierwszy element wiersza el a następnie jest on zwiększany z przyrostem 4. Umieszczenie samej nazwy macierzy a spowoduje wyświetlenie jej wszystkich elementów. 25 Generowanie macierzy - w podwójnej pętli (2) Przykład 1b. Wygenerować macierz A: 1 5 9 13 3 7 11 15 5 9 13 17 7 11 15 19 Ta sama macierz jest tutaj generowana inaczej. W pętli zewnętrznej otrzymujemy ciąg pierwszych elementów każdego wiersza i a w pętli wewnętrznej kolejne elementy wiersza j Numery wierszy w oraz kolumn k są otrzymywane osobno. % Program 2 clear; w=0; for i=1:2:7 w=w+1; k=0; for j=i:4:i+3*4 k=k+1; A(w,k)=j; end end A, % wyświetli macierz 26 13
Generowanie macierzy - bez pętli Przykład 1c. Wygenerować macierz A: 1 5 9 13 3 7 11 15 5 9 13 17 7 11 15 19 Ta sama macierz jest tutaj generowana bez pętli. Użyto funkcji repmat(m,w,k) do replikowania (wielokrotnego powielania) danej macierzy M, w razy w dół oraz k razy w prawo % Program 3 % bez pętli clear; clc; x=0:4:13 X=repmat(x,4,1); y=(1:2:7)' Y=repmat(y,1,4) A=X+Y; A, % wyświetli macierz 27 Generowanie macierzy - w podwójnej pętli (3) Przykład 2. Wygenerować macierz trójkątną B: 9 0 0 0 0 0 7 9 0 0 0 0 5 7 9 0 0 0 3 5 7 9 0 0 1 3 5 7 9 0 clear; % rezerwujemy pamięć i zerujemy macierz: B(4,6) = 0; for w = 1:5 e = 11-2*w; k = 0; while e<10 k = k+1; B(w,k) = e; e = e+2; end end B 28 14
Generowanie tablic bez pętli c.d. - ciągi w roli indeksów zeros(w,k) - generuje macierz wypełnioną zerami, a potem do wybieranych cyklicznie elementów wstawiamy np. 11: >>A = zeros(4,5); A(1:2:3, 2:2:5)=11 A = 0 11 0 11 0 0 0 0 0 0 0 11 0 11 0 0 0 0 0 0 29 Generowanie tablic funkcjami macierzowymi Funkcja: zeros(w,k) - generuje macierz wypełnioną zerami np.: >>A = zeros(2,3) A = 0 0 0 0 0 0 ones(w,k) - generuje macierz wypełnioną jedynkami np.: >>A = ones(2,4) A = 1 1 1 1 1 1 1 1 30 15
Generowanie tablic funkcjami macierzowymi c.d. rand(w,k) - generuje macierz liczb pseudolosowych o rozkładzie równomiernym np.: >>A = rand(2,5) A = 0.9501 0.6068 0.8913 0.4565 0.8214 0.2311 0.4860 0.7621 0.0185 0.4447 eye(n) - generuje macierz jednostkową (kwadratowa N x N z jedynkami na przekątnej głównej i zerami w pozostałych miejscach) np.: >>A = eye(3) A = 1 0 0 0 1 0 0 0 1 31 Wczytywanie tablic z pliku Jeśli w pliku tekstowym o nazwie DANE1.TXT są dwie linie i w każdej po 4 liczby oddzielane odstępami: 2 4 6 8 3 6 9 12 to aby wczytać te liczby do macierzy można napisać następujące instrukcje: [plik1 info] = fopen('dane1.txt'); A = fscanf(plik1, '%f %f %f %f', [4, 2]) close(plik1) Ale UWAGA: dane czytane są z pliku wierszami ale umieszczane w macierzy kolumnami, dlatego po wczytaniu uzyskamy macierz: A = 2 3 4 6 6 9 8 12 Aby uzyskać to samo co w pliku trzeba macierz transponować: A=A. 32 16
6. Działania na macierzach 33 Dodawanie i odejmowanie macierzy - można wykonywać tylko na macierzach typu double o identycznych rozmiarach >> A=[-2, 1, 3; 5, 6, 2], B=[0.5, 1, 1.5; 3, 2, 1] A = -2 1 3 5 6 2 B = 0.5000 1.0000 1.5000 3.0000 2.0000 1.0000 >> A+B -1.5000 2.0000 4.5000 8.0000 8.0000 3.0000 >> A-B -2.5000 0 1.5000 2.0000 4.0000 1.0000 34 17
Dzielenie, mnożenie, potęgowanie macierzy Są dwie kategorie operacji mnożenia, dzielenia i potęgowania macierzy: Tablicowe - operatory z kropką:.*./.^ = działania na parach elementów macierzy o jednakowych rozmiarach Macierzowe (operatory bez kropki) - zgodne z definicjami działań na macierzach 35 Operatory działań Tablicowe - na elementach:.* mnożenie (par elementów).^ potęgowanie (każdego elementu)./ dzielenie (par elementów) Macierzowe - na macierzach: * mnożenie macierzowe ^ potęgowanie macierzowe (a^2 = a*a mnożenie macierzowe) / dzielenie prawostronne (x=a / b jest rozwiązaniem równania: x*b=a) \ dzielenie macierzowe (x=a\b jest rozwiązaniem równania a*x=b) 36 18
>> A=[1, -1, 2; 1, 2, 3], B=[2, 0, 1; 1, 0, 2] A = 1-1 2 1 2 3 B = 2 0 1 1 0 2 >> C=A.* B C = 2 0 2 1 0 6 >> D=A*B; % Mnożenie macierzowe - niewykonalne??? Error using ==> * Inner matrix dimensions must agree. Przykład mnożenia tablicowego -macierze muszą mieć takie same rozmiary. Przy mnożeniu macierzowym liczba kolumn w pierwszej musi być taka jak liczba wierszy w drugiej 37 Mnożenie macierzowe 38 19
>> M1=[2,0,1;3,2,1], M2=[2;3;4] M1 = 2 0 1 3 2 1 M2 = 2 3 4 >> W=M1*M2 W = 2*2 + 0*3 + 1*4 = 8 3*2 + 2*3 + 1*4 =16 Przykład mnożenia macierzowego - liczba kolumn w pierwszej macierzy musi być równa liczbie wierszy w drugiej 39 Transpozycja macierzy [. ] - czyli zamiana wierszy na kolumny: >> A=[1,3,4,5; 2,3,6,7] A = 1 3 4 5 2 3 6 7 >> B=A.' B = 1 2 3 3 4 6 5 7 40 20
Układ równań liniowych (1) 41 Układ równań liniowych (2) 42 21
Układ równań liniowych (3) 43 Układ równań liniowych (4) 44 22
Funkcje dla wielomianu roots(a) - pierwiastki wielomianu dla danego wektora współczynników a. Kolejność: począwszy od najwyższej potęgi polyval(a, xp) - wartość wielomianu dla danego wektora współczynników a oraz danej wartości zmiennej xp 45 46 23