Moniulotteinen algebra

Seuraa 
Viestejä45973
Liittynyt3.9.2015

Moniulotteinen algebra

Algebran mahdollisuuksiin liittyy myös sellainen työkalu, jolla rinnakkaisia syy-seurauksia voi pukea ja approksimoida kompakteiksi funktioiksi. Kun näytölle piirtää hiirellä suunnilleen juohevan käyrän, algebra onnistuu approksimoimaan annetun pistejoukon lyhyeksi funktioksi. Algebran taito on sen kyvyssä kuvata ilmiöitä ja luontoa.

Entä, kun näytölle piirtää erivärisiä käyriä. Valkoinen pistejoukko on lämpötila, keltainen tuulen suunta, oranssi vuodenaika, sininen edustaisi ilmankosteutta, jne. Jokainen pistejoukko voidaan kuvata yksittäisenä ilmiönä, mutta entä se funktio, joka kuvaisi yksistään koko joukon välisiä syy-seuraus suhteita?

Funktion relaatio voi olla myös epäsymmetrinen. Sääfunktion inputtina voi olla n-kappaletta herätteitä, ja outputtina vain yksi suhteellisen sumea parametri välillä 0-1, kannattaako lähteä kalaan, vai ei.

***

Tietokoneen voi ohjelmoida tutkimaan matematiikkaa. Pitävillä algebran aksioomilla ja ristiriidattomilla sarjakehitelmillä bittihirmu syventyy edelleen geometriaan ja symmetriaan. Lopullisessa ratkaisussa tietokone oli osittain joutunut luopumaan symbolisista käsitteistä, mitä on positiivinen, negatiivinen, reaalinen ja imaginaarinen. Algebran ei tarvitse ottaa kantaa, miten päin monitori on pöydälle laitettu.

Algebran algoritmit ovat vakioita, ja sen oliot voivat kuvata mitä tahansa. Yksi kauneimpia algebran kaavoja on pienimmän neliösumman polynomisovitus:

[code:156qbus6]k0∑xj^0 + k1∑xj^1 + k2∑xj^2 +,...,+ kn∑xj^(n+0) = ∑yjxj^0

k0∑xj^1 + k1∑xj^2 + k2∑xj^3 +,...,+ kn∑xj^(n+1) = ∑yjxj^1

k0∑xj^2 + k1∑xj^3 + k2∑xj^4 +,...,+ kn∑xj^(n+2) = ∑yjxj^2
...
k0∑xj^n + k1∑xj^(n+1) + k2∑xj^(n+2) +,...,+ kn∑xj^(n+n) = ∑yjxj^n[/code:156qbus6]
Jos kaavaan sijoitettava olio on validi ja itsensä kanssa tasapainossa, algebra käsittelee substanssia järkevin tuloksin, muutoin ei. Hyvä esimerkki on kvaternio. Algebra ei ota kantaa kvaternion sisäiseen laskulogiikkaan.

***

i^2 on -1, mutta mikä on se olio, joka korotettuna toiseen antaa tulokseksi -i? i:n seuralaisilla on mielenkiintoinen yhteys, |e^(xi+yj+zk+...)| = 1. Moniulotteinen algebra yhdistää myös piin ja luvun yksi. pii^z raja-arvo reaaliakselilla lähestyy arvoa 1, kun z-yksikkövektori viritetään yhä kauemmas ja kauemmas reaaliakselista. Samalla akseleiden itseisarvojen summa lähestyy piitä.

Seuraavassa recomplex -luvun yksinkertaiset laskusäännöt C++ esimerkein. Itse luokka istuu myös melkein sellaisenaan MatLab -työkaluun.

[list:156qbus6]~ recomplex
~ kertaluku
~ luokkamäärittely
~ yhteenlasku
~ vähennyslasku
~ kertolasku
~ kantavektoreiden tulot
~ jakolasku
~ abs(recomplex)
~ pow(recomplex, int)
~ ln(recomplex)
~ exp(recomplex)
~ pow(recomplex, double)
~ pow(recomplex, recomplex)
~ sin(recomplex)
~ cos(recomplex)
~ pienimmän neliösumman sovitusesimerkki
~ piin ja luvun yksi yhteys
~ koodiliite[/list:u:156qbus6]
***

~~~ recomplex ~~~

Kompleksiluku on recomplex -luvun aito osajoukko. Reaaliluvut ja imaginaariluvut ovat puolestaan kompleksiluvun aitoja osajoukkoja. Etuliite "re" viittaa takaisinkytkentään, saman peruslogiikan uudelleen toistamiseen seuraavassa mittakaavassa.

~~~ kertaluku ~~~

Kertaluku käy kahden potenssissa, 1, 2, 4, ..., 2^n. Reaaliluvut virittyvät kertaluvulla 1. Kompleksiluvut käyvät voimaan kertaluvulla 2. Kertaluvussa 4 kompleksiluvut saavat rinnalleen vastinlogiikalla toimivan olion. Niiden yhdiste mahdollistaa muun muassa yksinkertaiset funktiokuvaukset rinnakkaisille syy-seuraus -ilmiöille.

~~~ luokkamäärittely ~~~

C++ toteutti operaattoreiden kuormituksen, jolloin varsinkaan numeeristen struktuureiden laskuoperaatiot tietokoneella eivät poikkea tavanomaisesta suoraviivaisuudesta.

[code:156qbus6]class recomplex
{
public:

#define KERTALUKU 4
double e[KERTALUKU];

recomplex(void);
recomplex(double);
recomplex(double *);
recomplex(char*, ...);

recomplex(int);
recomplex(int, int);
recomplex(int, int, int, int);

friend void print(recomplex);
friend double abs(recomplex);

friend recomplex operator-(recomplex);
friend recomplex operator+(recomplex, recomplex);
friend recomplex operator-(recomplex, recomplex);

friend recomplex operator*(recomplex, recomplex);
friend recomplex operator/(recomplex, recomplex);

friend recomplex operator/(recomplex, double);
friend recomplex operator*(double, recomplex);
};[/code:156qbus6]
recomplex -määrittely pitää sisällään peruslaskutoimitukset, vastaluvun ja itseisarvon. Tämän lisäksi on arvojen tulostusfunktio, sekä arvojen muodostimet.

~~~ yhteenlasku ~~~

[code:156qbus6]recomplex operator+(recomplex a, recomplex b)
{
for (int n=0; n
a.e[n]+=b.e[n];
return a;
}[/code:156qbus6]
Jos C on vierasta, muutama sana siitä. C:n lähtökohtana on säästää arkkeja. Kaikki ylimääräinen ja tarpeeton jaarittelu on karsittu syntaksista pois. C:n operaattorit ovat hyvin efektiivisiä. Esimerkiksi +=, *=, /=, ... suorittavat ensin ko. operaation, ja sen perään sijoitus. a.e[n]+=b.e[n] tarkoittaa siis samaa kuin a.e[n]=a.e[n]+b.e[n]. Koska jälkimmäinen tyyli kuluttaa enemmän paperia, C:ssä käytetään saman asian lyhempää merkintätapaa a.e[n]+=b.e[n].

Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
recomplex B(7, 5, 3, 2);
print(A+B);[/code:156qbus6]
Tulostuu arvo 9 + 8i + 8j + 9k.

~~~ vähennyslasku ~~~

[code:156qbus6]recomplex operator-(recomplex a, recomplex b)
{
for (int n=0; n
a.e[n]-=b.e[n];
return a;
}[/code:156qbus6]
Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
recomplex B(7, 5, 3, 2);
print(A-B);[/code:156qbus6]
Erotuksen arvo on -5 - 2i + 2j + 5k.

~~~ kertolasku ~~~

[code:156qbus6]recomplex operator*(recomplex a, recomplex b)
{
int *KantavektoreidenTulot(void);
int *R=KantavektoreidenTulot();
int i, j, n=(int)KERTALUKU*2;

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

for (i=j=0; i
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
for (j=0; j
t[R[i*n+j]]+=x[i]*y[j];

for (i=j=0; i
t[i]=(double)(t[j] - t[j+1]);
return *(recomplex*) t;
}[/code:156qbus6]
Kertolasku vaatii ensin kantavektoreiden tulomäärittelyn. Tulon silmukointi ei ota kantaa muodollisiin positiivisen, negatiivisen, reaalisen, imaginaarisen, jne. määrittelyihin. Kertolaskun tulos palautetaan summamuotoon vasta viimeisessä silmukassa.

Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
recomplex B(7, 5, 3, 2);
print(A*B);[/code:156qbus6]
Tulos on -32 + 32i + 87k. Kertolasku on vaihdannainen. Jos A ja B ovat kompleksisia, tulos on kompleksinen:

[code:156qbus6]recomplex A(2, 3, 0, 0);
recomplex B(7, 5, 0, 0);
print(A*B);[/code:156qbus6]
Tulostuu -1 + 31i.

~~~ kantavektoreiden tulot ~~~

Kantavektoreiden tulot generoituvat rekursiivisella funktiolla. Taulukkoon on koottu kaikki kertalukuun 4 liittyvät kantavektoreiden tulot:

[code:156qbus6] # 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 |
---#----|----|----|----|----|----|----|----|[/code:156qbus6]
Esimerkiksi ijk = -i, ja erikoisesti k^2 = -i. Vaihdannaisuus säilyy, koska edelleen:

[list:156qbus6]ikj = jik = jki = kij = kji = -i[/list:u:156qbus6]
[code:156qbus6]void GeneroiKantavektoreidenTulot(int *R, int n)
{
int I=0, J=n-1, i;
int X=n, Y=J+n, j;
int k=KERTALUKU*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 < KERTALUKU*2)
{
GeneroiKantavektoreidenTulot(R, n+n);
}
}

int* KantavektoreidenTulot(void)
{
static int R[KERTALUKU*KERTALUKU*4]={-1};
if (R[0] == -1)
{
int AlussaOliSuoKuokkaJaNolla=0;
R[0] = AlussaOliSuoKuokkaJaNolla;
GeneroiKantavektoreidenTulot(R, 1);
}
return R;
}[/code:156qbus6]

~~~ jakolasku ~~~

[code:156qbus6]recomplex operator/(recomplex x, recomplex y)
{
recomplex z;

for (int i, n=KERTALUKU; n>=2; n/=2)
{
for (z=y, i=n/2; i
z.e[i]=-z.e[i];
x=x*z; y=y*z;
}

return x/y.e[0];
}

recomplex operator/(recomplex x, double k)
{
for (int i=0; i
x.e[i]/=(double)k;
return x;
}[/code:156qbus6]
Jakolaskussa jakajalle tuotetaan liittoluku, jolla kerrotaan jaettava ja jakaja. Jokaisen silmukka-askeleen lopussa jakajan akseliarvoja on puolet vähemmän (loput summautuvat nolliksi). Kun jakajan arvo on reaalinen, arvolla jaetaan jaettavan elementit. Esimerkiksi 2 + 3i + 5j + 7k liittoluku on 2 + 3i - 5j - 7k.

Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
recomplex B(7, 5, 3, 2);
print(A/B);[/code:156qbus6]
Jakolaskun tulos on 0.5488136 - 0.1575801i + 0.7181670j + 0.3977540k. Jos A ja B ovat kompleksisia, tulos on kompleksinen:

[code:156qbus6]recomplex A(2, 3, 0, 0);
recomplex B(7, 5, 0, 0);
print(A/B);[/code:156qbus6]
Tulostuu arvo 0.3918919 + 0.1486486i.

~~~ abs(recomplex) ~~~

[code:156qbus6]double abs(recomplex x)
{
recomplex z;
double r, c;
int i, j=1, n;

for (n=KERTALUKU; n>=2; n/=2, j+=j)
{
for (z=x, i=n/2; i
z.e[i]=-z.e[i];
x=x*z;
}

r=fabs(x.e[0]);
c=1.0/(double)j;
return pow(r, c);
}[/code:156qbus6]
Itseisarvossa x kerrotaan liittoluvullaan kertaantuvasti, kunnes sen arvo on kokonaan reaalinen. Sen jälkeen arvosta palautetaan j:n keräämä murtopotenssi.

Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
recomplex B(7, 5, 3, 2);
printf("%25.20f\n", abs(A/B));[/code:156qbus6]
C:n double on tarkka, koska tuloksen itseisarvo on täsmälleen 1.00000000000000000000

~~~ pow(recomplex, int) ~~~

[code:156qbus6]recomplex pow(recomplex x, int n)
{
if (n)
{
recomplex t=x;
int i=n<0? -n: n;
for (--i; i; i--) t=t*x;
return n>0? t: recomplex(1.0)/t;
}
else
{
return recomplex(1.0);
}
}[/code:156qbus6]
x^0 raja-arvo on 1, kun x lähestyy nollaa. Laskukoneilla on vaihtelevia tulkintoja, onko 0^0 likimain 1 vai keskeytetäänkö laskenta ja tulostetaan virhetilanne. Pienimmän neliösumman sovituksessa x^0 pitää olla 1 myös x:n arvolla nolla. Eksponentti n voi olla positiivinen tai negatiivinen kokonaisluku.

~~~ ln(recomplex) ~~~

Funktio ln palauttaa luonnollisen logaritmin parametristä c. Funktion pohjana on yhtälö e^x = c, ja sarja 1 + x + x^2/2! + x^3/3! + ... Sarja derivoidaan ja iteroidaan Newtonin menetelmällä tuntematon x. Iterointi on toteutettu osittain tarkentuvalla menetelmällä.

[code:156qbus6]recomplex ln(recomplex c)
{
double t;
recomplex fx, dx;
recomplex x1, x2;
recomplex z(1.0);
recomplex x(1.0), xx;
double max=3.14159265e+36;

for (int k=2; k<160; k++)
for (int j=0; j<160; j++)
{
xx=x; t=1.0;
fx=z+x; dx=z;

for (int i=2; i<=k; i++)
{
dx=dx+i*xx/(t*=i);
xx=xx*x; fx=fx+xx/t;
if (abs(fx)>max) break;
}

x1=x;
x=x-(fx-c)/dx;
x2=x;

if (k+1 < 160)
{
if (abs(x1-x2)<1e-15) break;
}
}
return x;
}[/code:156qbus6]

Esim.
[code:156qbus6]recomplex A(2, 3, 5, 7);
print(ln(A));[/code:156qbus6]
ln(A) = 2.1540786 + 0.2528957i + 1.0997125j + 0.6920135k

~~~ exp(recomplex) ~~~

[code:156qbus6]recomplex exp(recomplex x)
{
double t=1.0;
recomplex sum(1.0), xx;
const double max=3.14159265e+36;

sum=sum+(xx=x);

for (int i=2; i<160; i++)
{
xx = xx*x;
sum=sum+xx/(t*=i);
if (abs(xx)>max) break;
}

return sum;
}[/code:156qbus6]
Esim.
[code:156qbus6]recomplex x(2, 3, 5, 7);
recomplex y=ln(x);
print(exp(y));[/code:156qbus6]
Käänteisfunktiolla palautuu arvo 2 + 3i + 5j + 7k. Kompleksisella parametrillä tulos on kompleksinen:

[code:156qbus6]recomplex x(2, 3, 0, 0);
print(exp(x));[/code:156qbus6]
Arvo on -7.3151101 + 1.0427437i.

~~~ pow(recomplex, recomplex) ~~~

Funktio laskee tuloksen sarjasta 1 + x ln a + (x ln a)^2/2! + (x ln a)^3/3! + ...

[code:156qbus6]recomplex pow(recomplex a, recomplex x)
{
double t=1.000;
recomplex sum(1.0);
recomplex ln(recomplex);
recomplex y = x*ln(a), xx=y;
const double max=3.14159265e+36;

sum=sum+xx;

for (int i=2; i<160; i++)
{
xx = xx*y;
sum=sum+xx/(t*=i);
if (abs(xx)>max) break;
}

return sum;
}[/code:156qbus6]
Esim.
[code:156qbus6]recomplex e(2.71828182845904523536);
recomplex x(0, 2, 3, 5);
recomplex f=pow(e, x);[/code:156qbus6]
f saa arvon -1.7657933 + 1.1326319i + 0.6499619j - 1.9145850k, jonka itseisarvo on 1.

Todistus: W. R. Hamiltonin alkuperäinen intuitio 1800 luvulta moniulotteisesta algebrasta on tosi, kunnes löydetään sellainen luku ai + bj + ck + ..., jolla |e^(ai+bj+ck,...)| <> 1.

~~~ pow(recomplex, double) ~~~

[code:156qbus6]recomplex pow(recomplex x, double n)
{
recomplex pow(recomplex, recomplex);
return pow(x, recomplex((double)n));
}[/code:156qbus6]
Esim.
[code:156qbus6]recomplex x(3, -5, 7, -11);
print(pow(x, 1.44269504088896340736));[/code:156qbus6]
Tulos on 17.9857383 - 7.1862263i - 0.2117166j - 44.2425271k.

~~~ sin(recomplex) ~~~
~~~ cos(recomplex) ~~~

[code:156qbus6]recomplex sin(recomplex x)
{
double t=1.0000;
recomplex sum(0.0);
recomplex y=x*x, xx=x;
double max=3.14159265e+36;

for (int i=1, sg=0; i<160; i+=2, sg++)
{
if (sg&1) sum=sum-xx/t;
else /**/ sum=sum+xx/t;
xx=xx*y; t*=(i+1)*(i+2);
if (abs(xx)>max) break;
}
return sum;
}

recomplex cos(recomplex x)
{
double t=2.0000;
recomplex sum(1.0);
recomplex y=x*x, xx=y;
double max=3.14159265e+36;

for (int i=2, sg=1; i<160; i+=2, sg++)
{
if (sg&1) sum=sum-xx/t;
else /**/ sum=sum+xx/t;
xx=xx*y; t*=(i+1)*(i+2);
if (abs(xx)>max) break;
}
return sum;
}[/code:156qbus6]
Trigonometristen funktioiden arvot muodostetaan Taylorin sarjakehitelmillä.

Esim.
[code:156qbus6]recomplex x(0.2, 0.3, 0.5, 0.7);
recomplex alfa=sin(x);
recomplex beeta=cos(x);
print(alfa*alfa+beeta*beeta);[/code:156qbus6]
Antaa arvon 1 + 0i + 0j + 0k. Toisin sanoen sin^2 x + cos^2 x = 1.

~~~ pienimmän neliösumman sovitusesimerkki ~~~

Esim.

Eräs ilmiö liittyi aikaan siten, että ajanhetkellä 1 mitattiin arvo 14 + 8j + 11l - 3n. Ajanhetkellä 2 mitattiin arvo -3 + 10j + 15l - 7n. Todettiin, että ilmiön syy-seuraus noudatti likimain arvoja:

[code:156qbus6] x0 = 1, y0 = 14 + 8j + 11l - 3n
x1 = 2, y1 = -3 + 10j + 15l - 7n
x2 = 3, y2 = -12 + 14j + 20l - 11n
x3 = 4, y3 = -20 + 17j + 23l - 15n
x4 = 5, y4 = -25 + 19j + 24l - 17n
x5 = 6, y5 = -28 + 22j + 24l - 21n
x6 = 7, y6 = -27 + 24j + 23l - 24n
x7 = 8, y7 = -25 + 27j + 20l - 27n
x8 = 9, y8 = -23 + 27j + 17l - 28n
x9 = 10, y9 = -18 + 27j + 13l - 32n
x10 = 11, y10 = -13 + 28j + 11l - 33n
x11 = 12, y11 = -4 + 28j + 6l - 35n
x12 = 13, y12 = 1 + 28j + 2l - 35n
x13 = 14, y13 = 9 + 27j - 3l - 35n
x14 = 15, y14 = 15 + 26j - 6l - 35n
x15 = 16, y15 = 22 + 24j - 10l - 37n
x16 = 17, y16 = 26 + 21j - 13l - 37n
x17 = 18, y17 = 30 + 21j - 17l - 36n
x18 = 19, y18 = 33 + 17j - 18l - 35n
x19 = 20, y19 = 34 + 13j - 19l - 33n
x20 = 21, y20 = 32 + 11j - 17l - 32n
x21 = 22, y21 = 28 + 7j - 15l - 30n
x22 = 23, y22 = 22 + 2j - 11l - 29n
x23 = 24, y23 = 12 - 2j - 7l - 26n
x24 = 25, y24 = -1 - 8j + 0l - 22n[/code:156qbus6]
Graafisen tarkastelun perusteella ilmiölle päätettiin sovittaa kuutioparaabeli. Kun mittausvastinarvot sijoitetaan pienimmän neliösumman kaavaan, kuutioparaabelin kertoimiksi saadaan:

[code:156qbus6]f(x) = k0 + k1x^1 + k2x^2 + k3x^3, jossa

k0 = 31.479 + 2.882j + 2.508l + 1.642n
k1 = -20.364 + 4.297j + 8.735l - 4.578n
k2 = 2.068 + -0.179j - 1.029l + 0.124n
k3 = -0.052 + 0.000j + 0.027l + 0.001n[/code:156qbus6]
recomplex kuutioparaabeli kuvaa ilmiötä hyvin. Alkuperäisillä x:n arvoilla funktion arvot ovat:

[code:156qbus6]f(recomplex( 1)) = 13.131 + 7.000j + 10.241l - 2.810n
f(recomplex( 2)) = -1.394 + 10.758j + 16.080l - 7.009n
f(recomplex( 3)) = -12.409 + 14.152j + 20.185l - 10.950n
f(recomplex( 4)) = -20.227 + 17.181j + 22.720l - 14.628n
f(recomplex( 5)) = -25.163 + 19.842j + 23.846l - 18.038n
f(recomplex( 6)) = -27.528 + 22.134j + 23.725l - 21.175n
f(recomplex( 7)) = -27.638 + 24.053j + 22.520l - 24.035n
f(recomplex( 8)) = -25.805 + 25.598j + 20.393l - 26.612n
f(recomplex( 9)) = -22.342 + 26.766j + 17.506l - 28.903n
f(recomplex(10)) = -17.563 + 27.554j + 14.021l - 30.901n
f(recomplex(11)) = -11.782 + 27.961j + 10.100l - 32.602n
f(recomplex(12)) = -5.311 + 27.984j + 5.906l - 34.002n
f(recomplex(13)) = 1.536 + 27.621j + 1.600l - 35.095n
f(recomplex(14)) = 8.445 + 26.870j - 2.655l - 35.876n
f(recomplex(15)) = 15.103 + 25.728j - 6.697l - 36.342n
f(recomplex(16)) = 21.197 + 24.192j - 10.364l - 36.487n
f(recomplex(17)) = 26.413 + 22.261j - 13.493l - 36.305n
f(recomplex(18)) = 30.438 + 19.932j - 15.924l - 35.794n
f(recomplex(19)) = 32.959 + 17.203j - 17.493l - 34.946n
f(recomplex(20)) = 33.661 + 14.072j - 18.038l - 33.759n
f(recomplex(21)) = 32.232 + 10.535j - 17.397l - 32.226n
f(recomplex(22)) = 28.359 + 6.592j - 15.408l - 30.343n
f(recomplex(23)) = 21.727 + 2.239j - 11.909l - 28.106n
f(recomplex(24)) = 12.024 - 2.525j - 6.737l - 25.509n
f(recomplex(25)) = -1.064 - 7.704j + 0.269l - 22.547n[/code:156qbus6]
Algebra ei ota kantaa, mitä laatua millekin akselille on symbolisesti sovittu. Yksikkövektori l voi edustaa esimerkiksi lumisadetta milleinä.

Reaaliakselin, iin ja sen seuralaisten ominaisuuksiin liittyy merkillinen automatiikka , jossa eri laadut voivat keskenään kommunikoida. Kirjoitin koodiin leikillisen parametrin nimen, int AlussaOliSuoKuokkaJaNolla=0. Yksinkertaisuus on kaunista. Moniulotteinen algebra generoituu rekursiivisisesti arvosta nolla.

~~~ piin ja luvun yksi yhteys ~~~

[code:156qbus6]pii^i = 0.4132921 + 0.9105985i
pii^j = 0.9285246 + 0.6520791i + 1.1283584j + 0.2494993k
pii^k = 0.9285246 - 0.6520791i + 0.2494993j + 1.1283584k
pii^l = 0.9999269 + 0.0715485i + 0.6552022j + 0.0031253k + 1.1447206l + ...
jne.[/code:156qbus6]
Kun sarjasta tulostetaan reaaliakselin arvo ja toisaalta kaikkien akseliarvojen itseisarvojen summa, saadaan:

[code:156qbus6]pii^i => 0.41329211610159394260, 1.32389061531420870700
pii^j => 0.92852456972547570140, 2.95846134587583531300
pii^k => 0.92852456972547570140, 2.95846134587583531300
pii^l => 0.99992686864099666890, 3.14142541301091204900
pii^m => 0.99992686864099666890, 3.14142541301091204900
pii^n => 0.99992686864099666890, 3.14142541301091249300
pii^o => 0.99992686864099666890, 3.14142541301091293700
pii^p => 0.99999999999958444350, 3.14159265358890360500
jne.[/code:156qbus6]

Symbolisesti e on kuningas. Se hallitsee suvereenisti koko valtakuntaa. i on daami. Se liikkuu nopeasti ja kaikkialle. j on torni ja k vastaa kahta kevyttä upseeria. Sotilaita on kahdeksan.

~~~ koodiliite ~~~

Liitteenä on painovirheetön recomplex -luokka. Koodin pitäisi kääntyä ongelmitta kaikissa C++ kääntäjissä. main esimerkki laskee em. sarjaa 32 kertaluvun kokoisena.

[code:156qbus6]#include
#include
#include
#include /* gcc:ssä string.h */

class recomplex
{
public:

#define KERTALUKU 32
double e[KERTALUKU];

recomplex(void);
recomplex(double);
recomplex(double *);
recomplex(char*, ...);

recomplex(int);
recomplex(int, int);
recomplex(int, int, int, int);
recomplex(double, double, double, double);

friend void print(recomplex);
friend double abs(recomplex);

friend recomplex operator-(recomplex);
friend recomplex operator+(recomplex, recomplex);
friend recomplex operator-(recomplex, recomplex);

friend recomplex operator*(recomplex, recomplex);
friend recomplex operator/(recomplex, recomplex);

friend recomplex operator*(recomplex, double);
friend recomplex operator/(recomplex, double);

friend recomplex operator*(double, recomplex);
friend recomplex operator/(double, recomplex);

/* ~ mgn = luvun suuruus ~ */
friend double mgn(recomplex);
friend recomplex ln(recomplex);
friend recomplex exp(recomplex);
friend recomplex sin(recomplex);
friend recomplex cos(recomplex);
friend recomplex pow(recomplex, int);
friend recomplex pow(recomplex, double);
friend recomplex pow(recomplex, recomplex);
};

////////////////////////////////////////////////////////////////////////
// Muodostin recomplex(char*, ...) //
// //
// Esim. //
// //
// recomplex x("2d", 2, 3), x saa arvon 2.0000 + 3.0000i //
// recomplex y("2f", 1.2345, 6.7891), y saa arvon 1.2345 + 6.7891i //
// //
// - formaatissa annetaan ensin lukujen määrä, esim 2. //
// - d tarkoittaa, että luvut annetaan kokonaislukuina. //
// - f tarkoittaa, että luvut annetaan liukulukumuodossa. //
////////////////////////////////////////////////////////////////////////
recomplex::recomplex(char *f, ...)
{
int i, j, kpl=atoi(f), step;
memset(this, 0x00, sizeof(recomplex));
unsigned long P=(unsigned long)&f+sizeof(char*);

for (j=0; f[j]; j++)
{
if (f[j]=='d') step=4;
if (f[j]=='f') step=8;
}

step=step==4? sizeof(int): sizeof(double);
for (i=j=0; i
e[i] = step == sizeof(int)?
*(int*)P: *(double*)P;
}

recomplex::recomplex(void)
{
memset(this, 0, sizeof(recomplex));
}

recomplex::recomplex(double a)
{
memset(this, 0, sizeof(recomplex));
e[0]=a;
}

recomplex::recomplex(double *a)
{
int n=(int)sizeof(double);
memcpy(e, a, n*KERTALUKU);
}

recomplex::recomplex(int a)
{
memset(this, 0, sizeof(recomplex));
e[0]=a;
}

recomplex::recomplex(int a, int b)
{
memset(this, 0, sizeof(recomplex));
e[0]=a; e[1]=b;
}

recomplex::recomplex(int a, int b, int c, int d)
{
memset(this, 0, sizeof(recomplex));
e[0]=a; e[1]=b; e[2]=c; e[3]=d;
}

recomplex::recomplex(double a, double b, double c, double d)
{
memset(this, 0, sizeof(recomplex));
e[0]=a; e[1]=b; e[2]=c; e[3]=d;
}

recomplex operator+(recomplex a, recomplex b)
{
for (int n=0; n
a.e[n]+=b.e[n];
return a;
}

recomplex operator-(recomplex a, recomplex b)
{
for (int n=0; n
a.e[n]-=b.e[n];
return a;
}

recomplex operator-(recomplex a)
{
for (int n=0; n
a.e[n]=-a.e[n];
return a;
}

recomplex operator*(recomplex a, recomplex b)
{
int *KantavektoreidenTulot(void);
int *R=KantavektoreidenTulot();
int i, j, n=(int)KERTALUKU*2;

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

for (i=j=0; i
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
for (j=0; j
t[R[i*n+j]]+=x[i]*y[j];

for (i=j=0; i
t[i]=(double)(t[j] - t[j+1]);
return *(recomplex*) t;
}

void GeneroiKantavektoreidenTulot(int *R, int n)
{
int I=0, J=n-1, i;
int X=n, Y=J+n, j;
int k=KERTALUKU*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 < KERTALUKU*2)
{
GeneroiKantavektoreidenTulot(R, n+n);
}
}

int* KantavektoreidenTulot(void)
{
static int R[KERTALUKU*KERTALUKU*4]={-1};
if (R[0] == -1)
{
int EnsinOliNolla=0;
R[0]=(double)EnsinOliNolla;
GeneroiKantavektoreidenTulot(R, 1);
}
return R;
}

recomplex operator/(recomplex x, recomplex y)
{
recomplex z;

for (int i, n=KERTALUKU; n>=2; n/=2)
{
for (z=y, i=n/2; i
z.e[i]=-z.e[i];
x=x*z; y=y*z;
}

return x/y.e[0];
}

recomplex operator/(recomplex x, double k)
{
for (int i=0; i
x.e[i]/=(double)k;
return x;
}

recomplex operator*(double k, recomplex x)
{
for (int i=0; i
x.e[i]*=(double)k;
return x;
}

recomplex operator*(recomplex x, double k)
{
return k*x;
}

recomplex operator/(double k, recomplex x)
{
return recomplex(k)/x;
}

////////////////////////////////////////////////////////////////////////
// Jossain 20-alkion kohdalla, kun kantavektorin tunnus on suurempi //
// kuin 'z', kantavektorin tunnus saattaa olla jokin kirjaimesta //
// poikkeava merkki. Itse laskuoperaatioissa kantavektoreiden //
// symbolisiin tunnuksiin ei oteta kantaa. //
////////////////////////////////////////////////////////////////////////
void print(recomplex a)
{
printf("%0.7f ", a.e[0]);
for (int n=1; n
printf("%c %0.7f%c ", a.e[n]<0?
'-': '+', fabs(a.e[n]), 'h'+n);
printf("\n");
}

double abs(recomplex x)
{
recomplex z;
double r, c;
int i, j=1, n;

for (n=KERTALUKU; n>=2; n/=2, j+=j)
{
for (z=x, i=n/2; i
z.e[i]=-z.e[i];
x=x*z;
}

r=fabs(x.e[0]);
c=1.0/(double)j;
return pow(r, c);
}

double mgn(recomplex x)
{
double sum=0;
for (int i=0; i
sum+=fabs(x.e[i]);
return sum;
}

recomplex pow(recomplex x, int n)
{
if (n)
{
recomplex t=x;
int i=n<0? -n: n;
for (--i; i; i--) t=t*x;
return n>0? t: recomplex(1.0)/t;
}
else
{
return recomplex(1.0);
}
}

recomplex ln(recomplex c)
{
double t;
recomplex fx, dx;
recomplex x1, x2;
recomplex z(1.0);
recomplex x(1.0), xx;
double max=3.14159265e+36;

for (int k=2; k<160; k++)
for (int j=0; j<160; j++)
{
xx=x; t=1.0;
fx=z+x; dx=z;

for (int i=2; i<=k; i++)
{
dx=dx+i*xx/(t*=i);
xx=xx*x; fx=fx+xx/t;
if (mgn(fx)>max) break;
}

x1=x;
x=x-(fx-c)/dx;
x2=x;

if (k+1 < 160)
{
if (mgn(x1-x2)<1e-15) break;
}
}
return x;
}

recomplex exp(recomplex x)
{
double t=1.0;
recomplex sum(1.0), xx;
const double max=3.14159265e+36;

sum=sum+(xx=x);

for (int i=2; i<160; i++)
{
xx = xx*x;
sum=sum+xx/(t*=i);
if (mgn(xx)>max) break;
}

return sum;
}

recomplex pow(recomplex a, recomplex x)
{
double t=1.000;
recomplex sum(1.0);
recomplex ln(recomplex);
recomplex y = x*ln(a), xx=y;
const double max=3.14159265e+36;

sum=sum+xx;

for (int i=2; i<160; i++)
{
xx = xx*y;
sum=sum+xx/(t*=i);
if (mgn(xx)>max) break;
}

return sum;
}

recomplex pow(recomplex x, double n)
{
recomplex pow(recomplex, recomplex);
return pow(x, recomplex((double)n));
}

recomplex sin(recomplex x)
{
double t=1.0000;
recomplex sum(0.0);
recomplex y=x*x, xx=x;
double max=3.14159265e+36;

for (int i=1, sg=0; i<160; i+=2, sg++)
{
if (sg&1) sum=sum-xx/t;
else /**/ sum=sum+xx/t;
xx=xx*y; t*=(i+1)*(i+2);
if (mgn(xx)>max) break;
}
return sum;
}

recomplex cos(recomplex x)
{
double t=2.0000;
recomplex sum(1.0);
recomplex y=x*x, xx=y;
double max=3.14159265e+36;

for (int i=2, sg=1; i<160; i+=2, sg++)
{
if (sg&1) sum=sum-xx/t;
else /**/ sum=sum+xx/t;
xx=xx*y; t*=(i+1)*(i+2);
if (mgn(xx)>max) break;
}
return sum;
}

void main(void)
{
for (int i=1; i
{
recomplex e(3.14159265358979323846);
recomplex x;
x.e[i]=1.0;
x=pow(e, x);
print(x);

double sum=0.0;
for (int j=0; j
sum+=fabs(x.e[j]);

printf("\n%0.20f, %0.20f\n\n", x.e[0], sum);
}
}[/code:156qbus6]

Sivut

Kommentit (73)

Vierailija

Kaikkiin teorioihin tarjoaa hyvän kommentin seuraava vastaus, joka ei siis TODELLAKAAN ole itseni keksimä:
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong." - Richard Feynman

BlackKnight
Seuraa 
Viestejä320
Liittynyt28.3.2006

En minäkään jaksanut kaikkea tästä aloituksesta lukea. Tuli kuitenkin mieleen, että onko tässä nyt kyse lineaarialgebrasta? Moniulotteista algebraahan kutsutaan sillä nimellä. Ongelma on vain, että perinteinen lineaarialgebra, jossa suhteet esitetään esim. muodossa

y = Ax +Bu, missä y,x ja u ovat vektoreita ja A ja B matriiseja

elementtien väliset suhteet oletetaan lineaarisiksi. Oletko yrittänyt korvata lineaariset suhteet pieneimmän neliösumman funktiolla? Tällöinhän voisi periaatteessa kästellä myös muita kuin lineaarisia funktioita.

Minulla on kuitenkin sellainen käsitys, että tätä asiaa tutkitaan säätötekniikassa ja nimenomaan epälineaarisen säädön alueella.

Neutroni
Seuraa 
Viestejä26835
Liittynyt16.3.2005

Ovatko hyperkompleksiluvut ja kvaterniot tuttuja? Muuten veikkaan, että olet juuri keksinyt jommat kummat. Minulle tämä aihe ei ole niin tuttu, että äkkiä näkisin onko todella niin. Kaipa noita voi yleistää korkeampiin ulottuvuuksiin. Siinä oli vain jotain laskusääntöjä, jotka piti toteuttaa että määritelmä olisi mielekäs.

Neutroni
Seuraa 
Viestejä26835
Liittynyt16.3.2005
Joonas74
hmm... fraktaaligeometriaan lisäulottuvuudet olisivat tervetulleita.

Joo, noita neljän komponentin kompleksilukuja (hypeskomplekseja ja kvaternioita) käytetään tuottamaan kolmi -ja neliulottaisia fraktaaleja. Neljänneksi ulottuvuudeksi voi laittaa ajan, ja projisoida sitten ajan mukana muutuvan kolmiulotteisen fraktaalin näytölle.

Googleen hakusanat hypercomplex ja fractal tuottavat joitain linkkejä. Ainakin povrayllä voi itsekin piirtää noita ilman suurempaa koodausta.

Vierailija
_jone_

Symbolisesti e on kuningas. Se hallitsee suvereenisti koko valtakuntaa. i on daami. Se liikkuu nopeasti ja kaikkialle. j on torni ja k vastaa kahta kevyttä upseeria. Sotilaita on kahdeksan.

hmm.. eikös se fii symboli ole se kaiken luonnon luoja eli kuningas.. 1,6180... jne.
mutta heti kun on mukana kompleksiluvut niin e=2,7182.. on kyllä se avain erilukutasoihin..

Neutroni
Seuraa 
Viestejä26835
Liittynyt16.3.2005
Joonas74

Niinkö. Laita ihmeessä linkki, jossa Mandelbrotin joukon tai Newtonin prosessin kompleksitason kaltainen monimuotoisuus olisi 3D:nä. Jee, onko sellaisia? Joitakin 3D-fraktaalivirityksiä olen nähnyt, mutta ne ovat olleet niin rumia, ettei niissä katse ja mieli lepää samoin, kuin kompleksitason 2D kuvissa.

En minäkään ole läheskään yhtä hienoja 3D-fraktaaleja nähnyt kuin 2D-fraktaalit ovat. Joku niissä tökkii, en osaa sanoa mikä. Ne ovat jotenkin sotkuisemman oloisia kuin kauniit Mandelbrotit ja Juliat. Johtuneeko sitten visualisoinnin vaikeudesta. Noillehan kai pitäisi laskea tiettyä iteraatiomäärää vastaavien pintojen derivaatat varjostuksen laskemiseksi kunnolla, mikä näin äkkiä ajateltuna vaikuttaa hyvin haastavalta.

Sivut

Uusimmat

Suosituimmat