Tomáš Kalvoda, KAM FIT ČVUT, 2019
Tento notebook ukazuje jak v Sage pracovat s maticemi s prvky z různých těles (resp. nejen těles).
Připomeňme si nejprve základní pojmy. Mějme těleso a přirozená čísla . Potom , tedy zobrazení, které dvojici indexů přiřadí prvek z (ozn. ), nazýváme maticí s prvky z tělesa .
Matice si můžeme přirozeně představovat jako tabulku čísel indexovanou pomocí dvou indexů a . Konvečně se prvek klade do tého řádku a tého sloupce. Prvek je v levém horním rohu, v levém dolním rohu, v pravém dolním rohu a v pravém horním rohu, konkrétně S přimhouřenýma očima bychom o maticích z programátorského pohledu mohli mluvit jako o dvourozměrných polích. Občas se také samotné prvky matice značí malým latinským písmenkem, tj. mohli bychom psát .
Indexu se říká řádkový index, indexu sloupcový index. Pokud platí , pak mluvíme o čtvercových maticích, jinak o maticích obdélníkových.
Často je potřeba mluvit o a hlavně pracovat s jednotlivými řádky a sloupci matic. K tomu zavádíme jednoduché značení kompatibilní s Pythonem. Pokud budeme mluvit o matici zmíněné výše, tak pod symbolem máme na mysli její tý řádek, tj. a pod symbolem pak její tý sloupec, tj.
K vytváření matic v Sage vystačíme s Pythonovským polem, tzv. listem, a funkcí matrix.
List (pole) v pythonu se vytváří jednoduše pomocí hranatých závorek a může jako své prvky obsahovat všechno možné:
a = [1, 2, 'a']
a[1, 2, 'a']
V proměnné a je uložen Pythonovský list, na který se můžete v tomto případě dívat jako na pole, indexované od a mající tři prvky.
K prvkům se přistupuje opět pomocí hranatých závorek:
print(a[0])
print(a[1])
print(a[2])1 2 a
Matice v Sage nejjednodušeji zkonstruujeme pomocí funkce matrix, které předáme list listů představující požadovanou matici zadanou po řádcích (vnitřní listy tedy odpovídají řádkům naší matice).
A = matrix([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
show(A)S obyčejným listem bychom si pro práci s maticemi nevystačili.
Podívejte se, jaké metody jsou k dispozici pro a a jaké pro A.
S maticí v proměnné A teď budeme moci provádět spoustu užitečených operací.
V úvodní části této sekce jsme nespecifikovali odkud máme prvky matice brát. Sage opět se v tomto případě snaží uhodnout, nad jakým tělesem se pohybujeme.
A.parent()Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
Tj. bez dalšího vysvětlování náš vstup chápe jako matici s prvky z množiny celých čísel , tedy jako prvek .
Ve většině případů není potřeba toto chování měnit, například v následujících případech je výsledek takový, jaký jsme zřejmě chtěli:
A = matrix([
[1/2, 2/3],
[4/5, 5/6]
])
show(A)
A.parent()Full MatrixSpace of 2 by 2 dense matrices over Rational Field
A = matrix([
[0.5, 2.2],
[0.3, 1.1]
])
show(A)
A.parent()Full MatrixSpace of 2 by 2 dense matrices over Real Field with 53 bits of precision
Občas chceme ale vynutit typ prvků matice, například když pracujeme nad konečným tělesem.
V tom případě je nejsnazší předat toto těleso jako první argument funkce matrix.
Například:
A = matrix(GF(5), [
[2, 4],
[1, 3]
])
show(A)
A.parent()Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
Na první pohled se nezdá, že se od prvního příkladu moc nezměnilo. Ale jak si ukážeme níže, výsledky různých maticových operací budu podstatně jiné, než kdybychom ji chápali jako prvek . Nyní jde o matici z .
Ukážeme si různé jednoduché způsoby jak přistupovat k prvkům matice A definované hned nad tímto dostavcem.
Jednotlivé prvky dostaneme tak jak jsme si zavedli indexování (pozor, v Sage i Pythonu od )!
print('Prvky v prvním řádku:')
print(A[0, 0])
print(A[0, 1])
print('Prvky v druhém řádku:')
print(A[1, 0])
print(A[1, 1])Prvky v prvním řádku: 2 4 Prvky v druhém řádku: 1 3
Nebo bychom mohli získat jednotlivé sloupce a řádky (to se nám bude hodit později).
print('První řádek:')
show(A[0,:])
print('Druhý sloupec:')
show(A[:,1])První řádek:
Druhý sloupec:
Matice z můžeme přirozeně násobit číslem z tělesa . Pod maticí rozumíme matici, jejíž prvky jsou -násobky prvků matice , přesněji pro každé a .
V Sage této operaci odpovídá * pokud nalevo máme číslo a napravo matici.
A = matrix(QQ, [
[1, 1/2],
[3, 3/5]
])
show(7 * A)Důležité je uvědomit si, že operace násobení mezi prvky matice se provádí v tělese !
A = matrix(GF(7), [
[1, 3],
[2, 5]
])
show(2 * A)Matice stejných rozměrů s prvky ze stejného tělesa můžeme přirozeně sčítat prvek po prvku, pro každé a .
V Sage této operaci odpovídá + mezi maticemi stejných rozměrů.
Podobně bude přirozeně fungovat operátor -.
A = matrix(QQ, [
[1, 1/2, 1/3],
[3, 2, 1]
])
B = matrix(QQ, [
[-1, -1, -1],
[1/2, 0, 1/2]
])
show(A + B)Důležité je uvědomit si, že operace sčítání mezi prvky matice se provádí v tělese !
A = matrix(GF(7), [
[1, 2, 3],
[5, 5, 2]
])
B = matrix(GF(7), [
[6, 1, 1],
[2, 4, 3]
])
show(A + B)Tato operace mezi maticemi může při prvním setkání vypadat poněkud komplikovaně.
Mějme matice a . Tedy má stejně sloupců jako řádků. Součinem těchto dvou matic je matice jejíž prvky jsou dány následovně pro každé a .
Pokud se nad uvedenou sumou zamyslíme, tak vidíme, že prvek součinu na tém řádku a tém sloupci vznikl tak, že jsme vzali tý řádek matice a tý řádek matice (tyto mají stejný počet prvků), vynásobili jsme je člen po členu (vnitřek sumy) a součiny sečetli (suma).
V tento okamžik se tato operace může zdát velmi "libovolná". Později během semestru si ukážeme, jak se k ní lze velmi přirozeně dostat při studiu lineárních zobrazení a jejich skládání.
V Sage této operaci odpovídá operátor * mezi maticemi správných rozměrů.
Vezměmě konkrétní příklad.
A = matrix(QQ, [
[1, 1/2, 1/3],
[3, 2, 1]
])
B = matrix(QQ, [
[-1, -1, -1],
[1/2, 0, 1/2],
[3, 4, 5]
])
show(A)
show(B)
print('Součin:')
show(A * B)Součin:
Pojďme si tento výsledek podrobněji rozebrat a spočtěme prvek v prvním řádku a druhém sloupci.
Ten by měl vzniknout tak, že vezme první řádek matice A a druhý sloupec matice B,
show(A[0, :])
show(B[:, 1])vynásobíme je prvek po prvku a výsledky sečteme, dostaneme tak očekávaný výsledek
sum(A[0, j] * B[j, 1] for j in range(3)) # range(3) = {0, 1, 2}, více méně1/3
Poznámka: Speciálně platí, že čtvercové matice stejného rozměru můžeme násobit dle libosti. Pro opakované násobení se přirozeně používá zkrácené značení ( matic vynásobených samo se sebou).
A = matrix([
[1, 2],
[3, 4]
])
show(A^5)Poznámka: Další operací, kterou s maticemi lze provádět je inverze. Té se budeme věnovat později během semestru.
Poznámka: Operace násobení i sčítání matic jsou asociativní. Distributivita maticového násobení vůči sčítání také platí. Násobení matic ovšem není komutativní!!!
Následující výpočet není důkaz těchto tvrzení, pouze demonstrace o čem mluvíme.
A = matrix(QQ, [
[1, 3],
[1, 2]
])
B = matrix(QQ, [
[1, -3],
[3, 0]
])
C = matrix(QQ, [
[0, -1],
[1, 0]
])
print('A + (B + C) == (A + B) + C:')
print(A + (B + C) == (A + B) + C)
print('A * (B * C) == (A * B) * C:')
print(A * (B * C) == (A * B) * C)
print('A * (B + C) == (A * B) + (A * C):')
print(A * (B + C) == (A * B) + (A * C))
print('A * B != B * A:')
print(A * B == B * A)A + (B + C) == (A + B) + C: True A * (B * C) == (A * B) * C: True A * (B + C) == (A * B) + (A * C): True A * B != B * A: False
Opravdu, součiny těchto dvou matic jsou:
show(A * B)
show(B * A)V tomto dodatku probereme pár užitečných způsobů jak konstruovat různé matice.
Matice s dvěma řádky a čtyřmi sloupci s náhodně zvolenými prvky z tělesa .
show(random_matrix(GF(3), 2, 4))Náhodná matice stejného rozměru, pouze s prvky zvolenými z tělesa racionálních čísel .
show(random_matrix(QQ, 2, 4))Nulová matice (matice se všemi prvky nulovými) s čtyřmi řádky a třemi sloupci.
show(zero_matrix(4, 3))Matice rozměru se všemi prvky rovnými .
show(matrix(4, 4, 2))
matrix?Jednotková matice (matice s jedničkami na diagonále a nulami všude jinde) rozměru .
show(identity_matrix(5, 5))Uvedené funkce umožňují i další možnosti jak matice konstruovat. Zvídavý čtenář se může inspirovat v dokumentaci. Alespoň jeden zajímavý netriviální příklad si uveďme.
f = lambda i, j: 1/(1 + i + j) # funkce dvou proměnných, f(i, j) = 1/(1 + i + j)
m = matrix(QQ, 5, 5, f) # matice mající prvky zkonstruované pomocí uvedené funkce
show(m)