Kristjan Kannike

Maatriksvõrrandites “skalaarsete” liikmete korrutamine ühikmaatriksiga

Maatriksvõrrandites on “skalaarse välimusega” liikmed vaikimisi võrdelised ühikmaatriksiga. Kuidas Mathematicas neid ühikmaatriksiga korrutada?

Konventsiooni järgi näeb kas terve avaldis välja nagu skalaar (näiteks null) või on maatriksitele liidetud skalaarsed liikmed.

Esimesel juhul on lahendus lihtne: kui avaldis eq on FreeQ[eq, List], korrutame teda ühikmaatriksiga.

Teisel juhul peame esmalt sikud lammastest eemal hoidma. Plus on vaikimisi Listable: liites skalaari vektorile või maatriksile, liidab Mathematica skalaari kõigile massiivi elementidele. Et seda vältida, kõrvaldame atribuudi Listable: ClearAttributes[Plus, Listable];

Lineariseerige oma funktsioonid

Kui Plus pole Listable, ei jää mitte ainult skalaaride ja listide summad nagu 1 + {2, 3}, vaid ka listide summad {1, 2} + {3, 4} välja arvutamata.

Seetõttu on funktsioonide nagu maatriksi jälg väljaarvutamine takistatud, kui nad pole defineeritud oma argumentides lineaarsetena. Jälg teeb listidest skalaarid; kuid praegu jäävad listid tema alamavaldisteks, muutes kasutuks allolevad mustrid. Peame Unprotect[Tr]; Tr[a_ + b_] := Tr[a] + Tr[b]; Protect[Tr];

Eksimatu teisendus ühikmaatriksite lisamiseks on eq = eq//.x_ + y_ :> x IDM + y /; FreeQ[x, List] && (!FreeQ[y, List]) && FreeQ[x, IDM];

Uurime seda lähemalt. Leiame summas kaks liiget: skalaari x ja y, milles on vähemalt üks List (et muster ei sobiks maatriksite elementidega). Vältimaks lõpmatut ReplaceRepeated (//.) tsüklit, nõuame, et x oleks FreeQ[x, IDM]. Hiljem asendatakse IDM ühikmaatriksiga.

Liige y ei saa lihtsalt olla list: avaldises a + b (c + M), ei korrutata a liiget IDM-iga, kuna b (c + M) pole list; kuid ta sisaldab listi, ja teisendus töötab.

Tähistame skalaare väike- ja maatrikseid suurtähtedega.

 Kahjuks takerdub eksimatu teisendus praktilistel juhtudel kombinatoorikasse; isegi lihtne avaldis nagu c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + {{a, b}, {c, d}} võtab minu arvutil 3.16 sekundit.

Võime proovida jagada tingimuse mustri liikmete vahel, et panna teda sobimatuse korral kiiremini lõpetama: (x_ /; FreeQ[ x, List] && FreeQ[x, IDM]) + (y_ /; !FreeQ[y, List]) -> x IDM + y;

Eelmise avaldise teisendamiseks kulub 2.12 sekundit, tervelt 1/3 korda vähem. Kuid see aeg on siiski vastuvõetamatu ja kasvab kiiresti teisendatava avaldise keerukuse kasvades. Mõni praktiline juht võtaks minuteid.

Peame olema konkreetsemad. Katsetame teisendust (x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + {X__} -> x IDM + {X};

Siin eeldame, et teine liige on list. See ei ole enam eksimatu; tõepoolest, ta katkestab mõnel valel kohal, nagu ülal märgitud. Kuid teisenduseks kulub keskmiselt vaid 0.03 sekundit — praktiliste juhtude jaoks nagu MSSM renormrühma võrrandid.

Teame juba üht erijuhtu, millega meie muster ei sobi: a + b (A + c). (Kordaja b on siin oluline — temata oleksid sulud liigsed.)

Selle leiab (x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + c_ ({Y__} + y_) -> x IDM + c({Y} + y);

Loomulikult leiab viimane ka üldisemaid avaldisi rohkemate liikmetega nagu a + b + c (d + {{a, b}, {c, d}} + e + f); tänu liitmise assotsiatiivsusele (sellele, et Plus on Flat). — Ta leiab isegi a + b (A + B) sarnased avaldised, kuna me ei olem nõudnud, et y oleks skalaar.

On veel üks klass erijuhte: maatrikskorrutisega a + c A.(b + B), mille leiab(x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + c_.*Dot[Y_, Z_] -> x IDM + c Dot[Y, Z];

Mathematica eeldab, et punkt tähistab pigem valikulist muutujat, mitte maatrikskorrutist, mistõttu peab kasutama c_.*Dot[Y_, Z_] lühema c_.*Y_.Z_ asemel.

Siin on oluline, et võime alati eeldada, et maatrikskorrutist sisaldav liige ongi maatriks. (Võimaluse, et Dot tähistab vektorite skalaarkorrutist, saab välistada, kui kontrollime, et võrrandi algtingimus on antud ruutmaatriksiga.) Tänu sellele ei pruugi me eraldi arvestada iga mõistlikku erijuhtu. Dot[Y_, Z_] leiab isegi avaldise nagu A.B.C, kuna Dot on Flat just nagu Plus.

Kordaja c võib seal olla või mitte. Kahjuks Mathematica ei arvuta kohapeal välja kordaja c maatriksi A korrutist, kuid kahe erineva mustri tegemist saab vältida, tehes c valikuliseks (kirjutades ta järele punkti: c_.). Kui mõnes avaldises pole vastavat kordajat, asendatakse c 1-ga.

Kasutades iga mustrit kolmest eraldi korduvas asenduses, on lõplik teisenduseq //.(x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + {X__} -> x IDM + {X}
//. (x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + c_ ({Y__} + y_) -> x IDM + c ({ Y} + y)
//. (x_ /; FreeQ[x, List] && FreeQ[x, IDM]) + c_.*Dot[Y_, Z_] -> x IDM + c Dot[Y, Z]
ja jääb vaid taastadaSetAttributes[Plus, Listable];

Teisendus ei tööta, kui skalaar on kahe vektori skalaarkorrutis.

Kui kaua kogu teisendus võtab? Mõnede tõsielujuhtude jaoks keskmiselt 0.29 sekundit, vahemikus 0.015 kuni 2.109 sekundit. Seda pole vähe. Kuid kui näiteks tuleb lahendada samu võrrandeid korduvalt erinevate algtingimustega, ja teisendust peab tegema vaid korra, võrrandeid sisse lugedes, on see talutav.