Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Recomplex, ja se miksei se ei toimi

kanjuha [16.02.2024 08:13:23]

#

Lausumakelvoton otsikko, menee kieli solmuun.
Tuli tässä edellisiltana seikkailtua kansan koodien läpi putkassa, niin kuin välillä tuppaa huvikseen tekemään. Ajoittain täällä on jotain hauskaa tai kiinnostavaakin. Tänään sattui silmiin eräs jone2712, tarkemmin tämä sekä tuo viestiketju. Aiheena on moniulotteinen algebra, joka on äärimmäisen kiinnostava aihe erityisesti ohjelmoinnissa. Kvaternionit jo ovatkin jo useimmille tuttuja, mutta esim. geometrinen algebra joka voi tietyissä sovelluksissa olla erinomainen vaihtoehto ja työkalu on paljon vähemmän tuttu. Tällaisena matematiikkafanina kiinnostuin kyseisestä projektista ja aloin sitten katselemaan että mitä siinä tarkemmin ajettiin takaa. Tässä kello viideltä aamuyöstä asian viimein selvittäneenä ajattelin kirjoittaa siitä hieman tännekin siltä varalta että ketään sattuisi matematiikka ja/tai ohjelmointi kiinnostamaan. Eräänlainen write-up menetetystä yöstä.

Mitä siinä tarkemmin ajettiin takaa

Suoraan sanottuna, ei mitään hajua. Koko homma alkaa valtavalla kommentilla joka selittää jotain käyristä ja korrelaatioista, enkä itse ainakaan saa asiasta päätä enkä häntää, eikä ketjun perusteella saanut kukaan muukaan. Kuitenkin selvää on, että tarkoitus on jatkaa kompleksilukuja useampaan ulottuvuuteen – samoin kuin kvaternioneissa ja Clifford-algebroissa. Kuten reaali- ja kompleksiluvutkin, näiden recomplex-lukujen olisi tarkoitus täyttää kunta-aksioomat: joukko ehtoja, jotka määrittävät sen miten "tavalliset" luvut käyttäytyvät. Lisäksi recomplex-luvut sisältäisivät aiemmat lukujoukot, eli kuten kompleksiluvut pelkistyvät reaaliluvuiksi jos imaginääriosa on nolla, niin recomplex-luvut pelkistyisivät kompleksiluvuiksi jos kaikki komponentit ensimmäistä kahta lukuunottamatta ovat nollia.

Kenelle tahansa, joka on koskaan päässyt ja/tai joutunut työskentelemään kvaternionien kanssa pitäisi olla muistissa se, ettei kvaternionit toimi kuin tavalliset luvut. Siinä missä reaali- ja kompleksilukuja voidaan pyörittää normaalien laskusääntöjen mukaan, kvaternionien kertolasku ei ole vaihdannaista, eli jos q ja v ovat kvaternionilukuja niin q·v ≠ v·q kaikille luvuille. Sama pätee Cliffordin algebroissa sekä niiden alialgebroissa, kun siirrytään neljään tai useampaan ulottuvuuteen. Siirtyessä korkeampaan määrään ulottuvuuksia tilanne sen kuin pahenee, sillä muun muassa Cayley-Dicksonin kaavalla määritellyt hyperkompleksiset lukujärjestelmät, joihin lukeutuvat sekä reaali- ja kompleksiluvut että kvaternionit, menettävät suuremmissa ulottuvuuksissa vieläkin enemmän ominaisuuksia: oktonionit menettävät liitännäisyytensä ja sedenionit (16 ulottuvuutta) menettävät alternatiivisuutensakin. Kunta-aksioomiin kuitenkin kuuluvat kaikki nämä ominaisuudet. Tuntuisi siltä, että jos recomplexin kaltainen kunta-aksioomat täyttävä neliulotteinen lukujärjestelmä olisi mahdollinen, se olisi jo paljon laajemmassa käytössä kuin kvaternionit ovat matematiikassa, sillä se olisi kompleksilukujen luonnollisin jatke.

Tästä syystä, ja matemaattisen pioneerimme aiemmasta kommelluksesta johtuen ainoa järkevä teko on tässä tilanteessa lähteä tutkimaan asiaa. Koodissahan ajetaan takaa mahdottomuudelta tuntuvaa (ja kuten myöhemmin opin, Frobeniuksen lauseen kautta matemaattisesti mahdotonta) lukujärjestelmää.

Kunta-aksioomat

Tavoite recomplex-luvuilla on olla kunta, eli täyttää kunta-aksioomat. Tämä tekisi niistä tavallisten lukujen kaltaisia, ja niihin voisi käyttää kaikkia tavallisia laskusääntöjä. Koska kunta-aksioomat ovat keskeisiä, ne olisi syytä listata.

Kunta-aksioomat — kaikille kunnassa oleville luvuille x, y ja z pätee seuraavat ehdot:

Näiden kaikkien ehtojen täyttyessä joukko lukuja muodostaa kunnan, ja siihen voidaan soveltaa tavallisia laskusääntöjä. Vähintään yhden näistä on myös pakko olla epätosi recomplex-lukujen pohjalla, sillä neliulotteinen kunta jossa on määritelty jakolasku (käänteisalkio) on matemaattisesti mahdoton.

Miten recomplex-luvut toimivat (taikka eivät)?

Katsellaan tässä vain neliulotteisia recomplex-lukuja, sillä tulos todennäköisesti yleistyy jollei jopa vain vakavoidu korkeammissa ulottuvuuksissa. Recomplex-luvut määrittelee perinpohjaisesti kolme asiaa: lukujen joukko, yhteenlaskun määritelmä, ja kertolaskun määritelmä. Joukko on ℝ⁴, neliulotteisten reaalivektorien joukko, eli kaikki nelimonistot muotoa (a,i,j,k). Yhteenlasku on tavallinen vektorien yhteenlasku, eli kahdelle luvulle x = (a,i,j,k) ja y = (b,l,m,n) summa x+y = (a+b, i+l, j+m, k+n). Kertolasku on monimutkaisempi ilmiö. Jone tarjoaa koodissaan seuraavan määritelmän:

/******************************************************************************
* ~~~ multiplication ~~~                                                      *
*                                                                             *
* The multiplication first requires a product definition of the base vectors. *
* Looping the product does not editorialise to the formal positive, negative, *
* real, imaginary, etc. definitions. The product of the multiplication is     *
* returned to the sum form so far only in the last loop.                      *
******************************************************************************/
recomplex operator*(recomplex a, recomplex b)
{
    int *BasisVectors(void);
    int *R = BasisVectors();
    int i, j, n=DIMENSION*2;

    double x[DIMENSION*2];
    double y[DIMENSION*2];
    double t[DIMENSION*2];

    for (i=j=0; i<DIMENSION; i++, j+=2)
    x[j+1]=y[j+1]=t[j]=t[j+1]=0.0,
    x[j]=a.e[i], y[j]=b.e[i];

    for (i=0; i<n; i++)
    for (j=0; j<n; j++)
    t[R[i*n+j]]+=x[i]*y[j];

    for (i=j=0; i<DIMENSION; i++, j+=2)
    t[i]=(double)(t[j] - t[j+1]);
    return *(recomplex*) t;
}
// ... jonkin verran muuta koodia ...
/******************************************************************************
* ~~~ the products of the base vectors ~~~                                    *
*                                                                             *
* The products of the base vectors are generated by the recursive function.   *
* All the products of the base vectors associated with the order of 4 are     *
* assembled in the chart:                                                     *
*                                                                             *
*    #  1 | -1 |  i | -i |  j | -j |  k | -k |                                *
* ############################################                                *
*  1 #  1 | -1 |  i | -i |  j | -j |  k | -k |                                *
* ---#----|----|----|----|----|----|----|----|                                *
* -1 # -1 |  1 | -i |  i | -j |  j | -k |  k |                                *
* ---#----|----|----|----|----|----|----|----|                                *
*  i #  i | -i | -1 |  1 |  k | -k | -j |  j |                                *
* ---#----|----|----|----|----|----|----|----|                                *
* -i # -i |  i |  1 | -1 | -k |  k |  j | -j |                                *
* ---#----|----|----|----|----|----|----|----|                                *
*  j #  j | -j |  k | -k |  i | -i | -1 |  1 |                                *
* ---#----|----|----|----|----|----|----|----|                                *
* -j # -j |  j | -k |  k | -i |  i |  1 | -1 |                                *
* ---#----|----|----|----|----|----|----|----|                                *
*  k #  k | -k | -j |  j | -1 |  1 | -i |  i |                                *
* ---#----|----|----|----|----|----|----|----|                                *
* -k # -k |  k |  j | -j |  1 | -1 |  i | -i |                                *
* ---#----|----|----|----|----|----|----|----|                                *
*                                                                             *
* For example ijk = -i, and particularly k^2 = -i. Commutativity remains,     *
* because still:                                                              *
*                                                                             *
* ikj = jik = jki = kij = kji = -i                                            *
******************************************************************************/
void GenerateTheProductsOfTheBaseVectors(int *R, int n)
{
    int I=0, J=n-1, i;
    int X=n, Y=J+n, j;
    int k=DIMENSION*2;

    for (i=I; i<=J; i++)
    for (j=I; j<=J; j++)
    {
        R[i*k+X+j]=R[i*k+j]+X;
        R[(X+j)*k+i]=R[i*k+j]+X;
        R[(Y-i)*k+Y-j]=J-R[i*k+j];
    }

    if (n+n < DIMENSION*2)
    {
        GenerateTheProductsOfTheBaseVectors(R, n+n);
    }
}

int* BasisVectors(void)
{
    static int R[DIMENSION*DIMENSION*4]={-1};
    if (R[0] == -1)
    {
        int FirstThereWasZero=0;
        R[0x00]=(int)FirstThereWasZero;
        GenerateTheProductsOfTheBaseVectors(R, 1);
    }
    return R;
}

Koodi on kieltämättä epätavallista C/C++-koodiksi, ja käyttää paljon joko vanhentuneita tai suorastaan tyyliohjeissa kiellettyjä merkintöjä, joita en itse ainakaan ole tottunut suuremmin katselemaan. Pienellä katselulla voidaan kuitenkin selvittää, mitä koodissa tapahtuu.

Jokainen vektori muutetaan 4-vektorista 8-vektoriksi, jotta negatiivisilla kantavektoreilla on omat komponenttinsa. Tällöin joka toinen komponentti on positiivinen kantavektori ja siitä seuraava sen vastaluku. Esitystapoja on äärettömästi, mutta tässä valitaan järkevästi jättää koko vektori positiivisen kantavektorien komponenteiksi ja asettaa negatiiviset nollaan. Aiemmat parametrivektorit a ja b ovat nyt x ja y, ja kohdevektori on nimeltään t.

Sitten jokainen t:n komponentti asetetaan siten, että sen arvo on kaikkien kantavektoriparien, joiden tulo on taulukon mukaan kyseistä komponenttia vastaava kantavektori, vastaavien komponenttien tulojen summa. Selkeämmin, jos kantavektoreille e₁ ja e₂ pätee e₁e₂ = e₃ niin x[e₁]·y[e₂] on yksi arvon määrävän summan termeistä.

Mukavamman kaavan selvittäminen on hankalampi tehtävä, tosin onneksi itse omistan valkotaulun ja liikaa aikaa. Katsomalla taulukkoa ja tekemällä käsin voimme johtaa kertolaskulle matemaattisen kaavan: jos x = (a,i,j,k) ja y = (b,l,m,n) niin x·y = (ab -il -jn -km, al +bi +jm -kn, am +bj -in -kl, an +bk +im +jl). Kantavektorien kertotaulun symmetrisyydestä voimme suoraan päätellä tulon vaihdannaisuuden, joka ei päde mm. kvaternioneille.

Tällä kaavalla recomplex-luvut ovat kokonaisuudessaan määritelty, ja niiden ominaisuuksia voi tutkia. Käänteisluvun määritelmän voisi johtaa itse kertolaskukaavasta, tai sen voi käsittämättömän muotonsa vuoksi käydä lainaamassa alkuperäisestä koodista. Tässä kohtaa on täysin mahdollista toteuttaa Python-implementaatio kyseisistä luvuista:

def recomplex_mul(x,y):
    a,i,j,k = x
    b,l,m,n = y

    return (
        a*b -i*l -j*n -k*m,
        b*i +a*l +j*m -k*n,
        b*j +a*m -k*l -i*n,
        b*k +a*n +i*m +j*l,
    )


def recomplex_add(x,y):
    a,i,j,k = x
    b,l,m,n = y
    return (a+b, i+l, j+m, k+n)


def recomplex_sub(x,y):
    return recomplex_add(x, recomplex_mul((-1,0,0,0), y))


# i have no clue what this does honestly
def recomplex_div(x,y):
    z = [0,0,0,0]

    n = 4
    while n >= 2:
        for i in range(4):
            z[i] = y[i]
        for i in range(n//2,n):
            z[i] = -z[i]
        x = recomplex_mul(x,tuple(z))
        y = recomplex_mul(y,tuple(z))
        n //= 2

    return recomplex_mul(x, (1/y[0],0,0,0))

Alkuperäinen koodi tarjoaa kätevät esimerkit, joilla testata uudelleenimplementaation pätevyys. Laskutoimitukset tuottavat samat arvot kuin alkuperäisen esimerkeissä, joten voidaan olettaa käsinlaskun menneen oikein. Nyt on mahdollista käydä kunta-aksioomat läpi symbolisesti vaikkapa nimenomaisesti Pythonissa.

Kunta-aksioomien läpikäyntiä varten asensin sympy-symbolisen laskennan kirjaston ja kirjoitin seuraavan ohjelman:

def main():
    # let us prove all the field axioms,
    # shall we?

    x = tuple(sympy.symbols('a i j k'))
    y = tuple(sympy.symbols('b l m n'))
    z = tuple(sympy.symbols('c o p q'))

    recomplex_simp = lambda x: tuple(map(sympy.simplify, x))
    recomplex_test = lambda x,y: recomplex_simp(recomplex_sub(x,y))

    print("Field axioms for recomplex (4D)")
    print("Each equality a = b is represented by a value a - b")
    print("Each axiom is fulfilled when the value is (0,0,0,0)")
    print("-----")
    assoc_add_fst = recomplex_add(x, recomplex_add(y,z))
    assoc_add_snd = recomplex_add(recomplex_add(x,y), z)
    assoc_add = recomplex_test(assoc_add_fst, assoc_add_snd)
    print(f"Associativity of addition: {assoc_add}")

    assoc_mul_fst = recomplex_mul(x, recomplex_mul(y,z))
    assoc_mul_snd = recomplex_mul(recomplex_mul(x,y), z)
    assoc_mul = recomplex_test(assoc_mul_fst, assoc_mul_snd)
    print(f"Associativity of multiplication: {assoc_mul}")

    comm_add_fst = recomplex_add(x,y)
    comm_add_snd = recomplex_add(y,x)
    comm_add = recomplex_test(comm_add_fst, comm_add_snd)
    print(f"Commutativity of addition: {comm_add}")

    comm_mul_fst = recomplex_mul(x,y)
    comm_mul_snd = recomplex_mul(y,x)
    comm_mul = recomplex_test(comm_mul_fst, comm_mul_snd)
    print(f"Commutativity of multiplication: {comm_mul}")

    id_add = recomplex_test(recomplex_add(x, (0,0,0,0)), x)
    print(f"Additive identity: {id_add}")

    id_mul = recomplex_test(recomplex_mul(x, (1,0,0,0)), x)
    print(f"Multiplicative identity: {id_mul}")

    inv_add = recomplex_test(recomplex_add(x, recomplex_mul(x, (-1,0,0,0))),(0,0,0,0))
    print(f"Additive inverse: {inv_add}")

    inv_mul = recomplex_test(recomplex_mul(x, recomplex_div((1,0,0,0), x)), (1,0,0,0))
    print(f"Multiplicative inverse: {inv_mul}")

    distrib_fst = recomplex_mul(z, recomplex_add(x,y))
    distrib_snd = recomplex_add(recomplex_mul(z,x), recomplex_mul(z,y))
    distrib = recomplex_test(distrib_fst, distrib_snd)
    print(f"Distributivity: {distrib}")

if __name__ == "__main__":
    main()

Kaunis se ei välttämättä ole, mutta se hoitaa tehtävänsä mutkitta. Kustakin vaaditusta yhtälöstä a = b käytetään vaihtoehtoista muotoa a - b = 0, jolloin voidaan tulostaa arvo a - b ja poikkeaman sattuessa kyseinen poikkeama tulostuu näytölle tulkittavaksi välittömästi sanan False sijaan. Testatut ominaisuudet ovat järjestyksessä summan ja tulon liitännäisyys, niiden vaihdannaisuus, neutraalialkioiden toiminta, vasta- ja käänteisalkioiden toiminta sekä osittelulaki. Koska lukujen tilalle asetetaan symbolit, jotka esittävät mitä tahansa lukua, tulos on (0,0,0,0) jos ja vain jos matemaattisella symbolien pyörittelyllä saadaan aina luvusta riippumatta irti sama tulos yhtälön molemmilla puolilla.

Jäljellä ei ole kuin pyörittää kyseinen skripti.

λ python3 recomplex.py
Field axioms for recomplex (4D)
Each equality a = b is represented by a value a - b
Each axiom is fulfilled when the value is (0,0,0,0)
-----
Associativity of addition: (0, 0, 0, 0)
Associativity of multiplication: (0, 0, 0, 0)
Commutativity of addition: (0, 0, 0, 0)
Commutativity of multiplication: (0, 0, 0, 0)
Additive identity: (0, 0, 0, 0)
Multiplicative identity: (0, 0, 0, 0)
Additive inverse: (0, 0, 0, 0)
Multiplicative inverse: (0, 0, 0, 0)
Distributivity: (0, 0, 0, 0)

Jaa. No se ei todellakaan ollut haluttu tulos. Ohjelman mukaan kaikki kunta-aksioomat täyttyvät. Ei siinä mitään, lukujärjestelmän on pakko olla kelvoton joten yhden näistä on pakko rikkoutua joka tapauksessa. Tätä jonkin aikaa tuijoteltuani päätin kysyä apua muilta, ja mistä parempi kuin tietenkin vanhalta kunnon Stack Exchangelta. Kuitenkin ongelman esittämistä varten olisi hyvin mukava muotoilla vähän lisätietoa, kuten vaikkapa erilaiset oleelliset ominaisuudet LaTeX-muodossa esitettäväksi, taikka yksinkertaistettu kantavektorien kertotaulu tutkittavaksi.

Toinen on yllättävän helppo, ottaa vain vastaluvut pois vektoritaulukosta. Ensimmäinen ei niinkään, sillä matemaatikkoja ei välttämättä kiinnosta laiskasti kopioitu imperatiivinen algoritmi käänteislukujen numeeriseen selvittämiseen. Kaikeksi onneksi sympy on erittäin mukava kirjasto tätä ajatellen, luvun sijaan funktiolle voi antaa sympy-kirjaston muuttujia ja se sylkee toimivan kaavan ulos vaikkapa LaTeX-muodossa upottamista varten.

λ python3
Python 3.11.7 (main, Jan 29 2024, 16:03:57) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sympy
>>> from recomplex import *
>>> sympy.init_printing()
>>> x = sympy.symbols('a i j k')
>>> y = recomplex_div((1,0,0,0), x)
>>> tuple(map(sympy.simplify, y))
⎛  ⎛ 2    2        ⎞     ⎛         2    2⎞      ⎛         2    2⎞     ⎛ 2    2        ⎞      ⎛ 2    2        ⎞     ⎛         2    2⎞    ⎛         2    2⎞     ⎛ 2    2        ⎞⎞
⎜a⋅⎝a  - i  + 2⋅j⋅k⎠ + i⋅⎝2⋅a⋅i - j  + k ⎠  - a⋅⎝2⋅a⋅i - j  + k ⎠ + i⋅⎝a  - i  + 2⋅j⋅k⎠  - j⋅⎝a  - i  + 2⋅j⋅k⎠ - k⋅⎝2⋅a⋅i - j  + k ⎠  j⋅⎝2⋅a⋅i - j  + k ⎠ - k⋅⎝a  - i  + 2⋅j⋅k⎠⎟
⎜─────────────────────────────────────────, ───────────────────────────────────────────, ───────────────────────────────────────────, ─────────────────────────────────────────⎟
2                    2                      2                    2                       2                    2                      2                    2⎜ ⎛ 2    2        ⎞    ⎛         2    2⎞      ⎛ 2    2        ⎞    ⎛         2    2⎞       ⎛ 2    2        ⎞    ⎛         2    2⎞      ⎛ 2    2        ⎞    ⎛         2    2⎞  ⎟
⎝ ⎝a  - i  + 2⋅j⋅k⎠  + ⎝2⋅a⋅i - j  + k ⎠      ⎝a  - i  + 2⋅j⋅k⎠  + ⎝2⋅a⋅i - j  + k ⎠       ⎝a  - i  + 2⋅j⋅k⎠  + ⎝2⋅a⋅i - j  + k ⎠      ⎝a  - i  + 2⋅j⋅k⎠  + ⎝2⋅a⋅i - j  + k ⎠  ⎠
>>> ^D

Melkoinen hirviökaava.
Tässä kohtaa itsestäni poiketen kaikki joilla on silmät päässä on jo ratkaissut tilanteen. Kumminkin itse jatkan Stack Exchange -postauksen kirjoittamista tämän sijaan. Sen lähtetettyäni (huom. renderöity LaTeX-versio yllä olevista ASCII-muusikaavoista linkin takana) ja hetken ongelmia korjattuani tipahtaa eräältä kommentoijalta vastaus. Vektori (1,1,√2,0) ei käänny.

Se nimenomainen ongelma

Tulkki auki. Vektori sisään. Tulos ulos.

λ python3
Python 3.11.7 (main, Jan 29 2024, 16:03:57) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from recomplex import *
>>> from sympy import sqrt
>>> recomplex_div( (1,0,0,0), (1,1,sqrt(2),0) )
(nan, nan, nan, nan)
>>> ^D

Siinähän se.

Käänteisluvulle selvitetyssä hirviökaavassa on eräs erityispiirre useimpiin kaavoihin verrattuna. Siihen sisältyy jakolasku. Jos on olemassa jokin syöte, jolla nimittäjä saadaan nollaan, ei tälle luvulle ole määritelty käänteislukua.

Nimittäjä on (a² - i² + 2jk)² + (2ai - j² +k²)². Luvulle (1,1,√2,0) saamme sijoittamalla (1² - 1² + 2·1·0)² + (2·1·1 - √2² + 0²)² eli (1 - 1)² + (2 - 2)² eli 0² + 0² eli 0. Täten on olemassa luku, joka ei ole nolla, jolle ei ole käänteislukua, eikä käänteisalkioaksiooma täyty. Recomplex-luvut eivät muodosta kuntaa. Mysteeri ratkaistu.

Hieman koomisesti tämä on edelleen sama ongelma kuin edellisellä kerralla. Käänteisluvuttomia "nollia" on liikaa. Tällä kertaa tilanne on vain hyvin monimutkaisen koodin alla piilossa. Edellisellä kerralla kyseessä oli nollasuora. Nyt koska x² + y² = 0 johtaa siihen että x² = -y² ja koska x² ≥ 0 aina niin x² = y² = 0 niin sekä a² - i² + 2jk = 0 että 2ai - j² + k² = 0 jonka ratkaisusta lentää ulos monimutkaisempi neliöjuuriin pohjautuva neliulotteinen, kaikesta päätellen jatkuva pinta.

Neliulotteista kunnaksi kelpaavaa lukujärjestelmää ei tainnut ollakaan. Mutta miksi Python-ohjelma ilmoitti kunta-aksiooman pätevän?

Koska sympy ei kirjastona osaa päätellä asiaa kunnolla. Se ei osaa tarkastaa ja varoittaa siitä, että tietyllä tuntemattomalla arvolla on jaettu ja että yhtälöllä on siitä syystä uusia ehtoja joiden sisällä se pätee. Todellisuudessahan sympy oli täysin oikeassa siitä että x·x⁻¹ = 1 jos a² - i² +2jk ≠ 2ai - j² + k² eli kumpikaan ei ole nolla. Työkaluihin ei voi luottaa aivan liiaksiin, sillä välistä voi jäädä pari tärkeää askelta jotka täysin muuttavat vastauksen.

Mitä tästä opimme

Ensimmäisenä, vaikka matematiikan tutkiminen itsenäisesti on kunnioitettavaa, perustutkimus aiheeseen paljastaisi ettei recomplex-tyylinen lukujärjestelmä voi toimia, vaan siinä on pakolla reikiä jotka rikkovat yleiset laskusäännöt monta kertaa kvaternioneita ja geometrista algebraa pahemmin. Toisena, monimutkainen ja/tai optimisoitu koodi/kaava voi helposti piilottaa tappavan vian. On huomattavasti luotettavampaa käydä ensin matemaattisesti läpi, kirjoittaa matemaattiset kaavat koodiin missä mahdollista, ja kirjoittaa koodi ensin hitaaksi ja optimisoimattomaksi mutta selkeäksi ja optimisoida vasta jälkeenpäin. Kolmantena, matematiikka onnistuu paljon paremmin kun on hereillä eikä kello ole 3:00. Viimeisenä, älä koskaan unohda sitä että työkaluilla on rajoituksensa vaikka kyseessä olisi niinkin loogisesti jäykkä aihealue kuin matematiikka.

Mukava lyhyt tarina siitä miten nukuin yössä nolla (0) tuntia. Kiinnostava projektikin tuo recomplex. Itse jonena lukisin juurikin noista Cliffordin algebroista, sillä ne ovat n-ulottuvuuksisia suljettuja algebroita, ja vaikkeivat ne kuntia olekkaan, niin ne silti onnistuvat yleistämään reaali- ja kompleksiluvut sekä kvaternionit, ja olemaan harvinaisen hyödyllisiä tilanteissa missä kvaternionit ovat hyödyllisiä, mutta siitä huolimatta harvinaisen selkeitä erityisesti geometrisissa tilanteissa kuten 3D-kääntöjen matemaattisessa esittämisessä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta