This is old C++ code originally intended to be a playground for 3D math.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

503 lines
12 KiB

using namespace std;
#include <cstdio>
#include "Mmn.h"
/****************************************************************
* die Klasse "Mmn" *
****************************************************************/
//------ Kontruktoren -------------------------------------------
template <class K>
Mmn<K>::Mmn(K* a, unsigned m, unsigned n) : m(m), n(n), Rg(0), Det_F(false) {
_a=new (K*)[m];
for(unsigned i=0; i<m; i++) {
_a[i]=new K[n];
for(unsigned j=0; j<n; j++)
_a[i][j]=*(a+n*i+j);
}
}
template <class K>
Mmn<K>::Mmn(unsigned m) : m(m), n(m), Rg(0), Det_F(false) {
_a=new (K*)[m];
for(unsigned i=0; i<m; i++) {
_a[i]=new K[n];
for(unsigned j=0; j<n; j++)
_a[i][j]=(j==i)?1:0;
}
}
template <class K>
Mmn<K>::Mmn(unsigned m, unsigned n) : m(m), n(n), Rg(0), Det_F(false) {
_a=new (K*)[m];
for(unsigned i=0; i<m; i++) {
_a[i]=new K[n];
for(unsigned j=0; j<n; j++)
_a[i][j]=0;
}
}
template <class K>
Mmn<K>::Mmn(const Mmn<K>& A)
: m(A.m), n(A.n), Rg(A.Rg), Det(A.Det), Det_F(A.Det_F) {
_a=new (K*)[m];
for(unsigned i=0; i<m; i++) {
_a[i]=new K[n];
for(unsigned j=0; j<n; j++)
_a[i][j]=A._a[i][j];
}
}
template <class K>
Mmn<K>::~Mmn() {
freeall();
}
//---------------------------------------------------------------
//------ Operatoren ---------------------------------------------
template <class K>
const Mmn<K>& Mmn<K>::operator=(const Mmn<K>& A) {
if(this==&A)
return *this;
if(!_a || m != A.m || n != A.n) {
freeall();
_a=new (K*)[A.m];
for(unsigned i=0; i<A.m; i++)
_a[i]=new K[A.n];
}
m=A.m;
n=A.n;
Rg=A.Rg;
Det=A.Det;
Det_F=A.Det_F;
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
_a[i][j]=A._a[i][j];
return *this;
}
template <class K>
Mmn<K> Mmn<K>::operator*(const K& a) const {
Mmn<K> A(m,n);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
A._a[i][j]=_a[i][j]*a;
return A;
}
template <class K>
Mmn<K> Mmn<K>::operator%(const Mmn<K>& A) const {
if(n != A.m)
return null();
Mmn<K> B(m,A.n);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<A.n; j++) {
B._a[i][j]=0;
for(unsigned ji=0; ji<n; ji++)
B._a[i][j]+=_a[i][ji]*A._a[ji][j];
}
return B;
}
template <class K>
Mmn<K> Mmn<K>::operator+(const Mmn<K>& A) const {
if(n != A.n || m != A.m)
return null();
Mmn<K> B(m,n);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
B._a[i][j]=_a[i][j]+A._a[i][j];
return B;
}
template <class K>
Mmn<K> Mmn<K>::operator-(const Mmn<K>& A) const {
Mmn<K> B(m,n);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
B._a[i][j]=-A._a[i][j];
return *this+B;
}
//---------------------------------------------------------------
//------ Hilfsfunktionen ----------------------------------------
template <class K>
void Mmn<K>::freeall(void) {
if(_a) {
for(unsigned i=0; i<m; i++) {
delete [] _a[i];
}
delete [] _a;
_a=NULL;
}
m=n=Rg=0;
Det_F=false;
}
//---------------------------------------------------------------
//------ Determinantenberechnung --------------------------------
template <class K>
K Mmn<K>::sarrus(void) const {
return _a[0][0]*_a[1][1]*_a[2][2]\
+_a[0][1]*_a[1][2]*_a[2][0]\
+_a[0][2]*_a[1][0]*_a[2][1]\
-_a[0][1]*_a[1][0]*_a[2][2]\
-_a[0][0]*_a[1][2]*_a[2][1]\
-_a[0][2]*_a[1][1]*_a[2][0];
}
template <class K>
K Mmn<K>::laplace(void) const {
K detA=0;
Mmn<K> A;
// analytisches optimieren des Laplace-Algorithmus, durch finden der
// Zeile/Spalte mit den meisten Nullen.
//-------------------------------------------------------------------
unsigned nulls_in_line[m];
for(unsigned i=0; i<m; nulls_in_line[i++]=0);
unsigned nulls_in_col[n];
for(unsigned j=0; j<m; nulls_in_col[j++]=0);
unsigned max_nulls=0;
int max_nulls_line=0;
int max_nulls_col=0;
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
if(_a[i][j]==(K)0) {
nulls_in_line[i]++;
nulls_in_col[j]++;
if(nulls_in_line[i]>max_nulls)
max_nulls=nulls_in_line[i];
if(nulls_in_col[i]>max_nulls)
max_nulls=nulls_in_col[i];
// ist eine komplette Zeile oder Spalte 0, so koennen wir
// direkt abbrechen und 0 zurueckgeben.
if(max_nulls==m)
return (K)0;
max_nulls_line=(max_nulls==nulls_in_line[i])?i:max_nulls_line;
max_nulls_col=(max_nulls==nulls_in_col[j])?j:max_nulls_col;
}
if(nulls_in_line[max_nulls_line] > nulls_in_col[max_nulls_col]) {
A=T();
max_nulls_col=max_nulls_line;
}
else
A=*this;
//-------------------------------------------------------------------
for(unsigned i=0; i<A.m; i++)
if(A._a[i][0]!=(K)0)
detA+=((K)(int)pow((double)-1,(double)(i+max_nulls_col)))
*A._a[i][max_nulls_col]
*A.Aij(i,max_nulls_col).det();
return detA;
}
template <class K>
K Mmn<K>::det(void) const {
K Det=(K)0;
if(m!=n) {
return Det;
}
else {
switch(m) {
case 1: Det=_a[0][0];
break;
case 2: Det=_a[0][0]*_a[1][1]-_a[0][1]*_a[1][0];
break;
case 3: Det=sarrus();
break;
default: Det=laplace();
}
return Det;
}
}
template <class K>
K Mmn<K>::det(void) {
if(m!=n) {
Det=(K)0;
Det_F=false;
return Det;
}
else {
switch(m) {
case 1: Det=_a[0][0];
break;
case 2: Det=_a[0][0]*_a[1][1]-_a[0][1]*_a[1][0];
break;
case 3: Det=sarrus();
break;
default: Det=laplace();
}
Det_F=true;
return Det;
}
}
//---------------------------------------------------------------
//------ Matrizenmanipulationen ---------------------------------
template <class K>
Mmn<K> Mmn<K>::Aij(unsigned i, unsigned j) const {
Mmn<K> A(m-1,n-1);
unsigned _i, _l, _j, _k;
for(_i=0, _l=0; _i<m; _i++, _l++) {
if(_i==i) _i++;
if(_i>=m) break;
for(_j=0, _k=0; _j<n; _j++, _k++) {
if(_j==j) _j++;
if(_j>=n) break;
A._a[_l][_k]=_a[_i][_j];
}
}
return A;
}
template <class K>
Mmn<K> Mmn<K>::Ai(unsigned i) const {
Mmn<K> A(m-1,n);
unsigned _i, l;
for(_i=0, l=0; i<m; _i++, l++) {
if(_i==i) _i++;
if(_i>=m) break;
for(unsigned j=0; j<n; j++)
A._a[l][j]=_a[_i][j];
}
return A;
}
template <class K>
Mmn<K> Mmn<K>::Aj(unsigned j) const {
Mmn<K> A(m,n-1);
unsigned _j, k;
for(unsigned i=0; i<m; i++)
for(_j=0, k=0; _j<n; _j++, k++) {
if(_j==j) _j++;
if(_j>=n) break;
A._a[i][k]=_a[i][_j];
}
return A;
}
template <class K>
Mmn<K> Mmn<K>::T(void) const {
Mmn<K> A(n,m);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
A._a[j][i]=_a[i][j];
return A;
}
template <class K>
Mmn<K> Mmn<K>::Ad_det(void) const {
Mmn<K> A(n,m);
for(unsigned i=0; i<m; i++)
for(unsigned j=0; j<n; j++)
A._a[j][i]=((K)(int)pow((double)-1,(double)(i+j)))*Aij(i,j).det();
return A;
}
template <class K>
Mmn<K> Mmn<K>::Ad_inv(void) const {
// Das geht nur wenn die Determinante nicht 0 ist, da sonst die ganze
// Ergebnismatrix automatisch 0 wird, was aber nicht unbedingt sein muß.
// Dies gilt insbesondere Wenn die Matrize eine Null-Zeile oder Spalte
// enthaelt.
K d=Det_F?Det:det();
if(d != (K)0)
return d*gauss(INVERSE);
else
return Ad_det();
}
template <class K>
Mmn<K> Mmn<K>::inv_Ad(void) const {
K Adet;
if((Adet=Det_F?Det:det())==(K)0) {
return null();
}
else {
return Ad_det()*((K)1/Adet);
}
}
template <class K>
Mmn<K> Mmn<K>::gauss(gauss_typ T) const {
Mmn<K> A=*this;
Mmn<K> B(m);
for(unsigned i=0; i<A.m; i++) {
unsigned j;
for(j=i; j<A.n; j++) {
unsigned k;
for(k=i; k<A.m && A._a[k][j]==(K)0; k++);
if(k==A.m)
continue;
if(k!=i) {
K* tmp=A._a[i];
A._a[i]=A._a[k];
A._a[k]=tmp;
if(T==INVERSE) {
tmp=B._a[i];
B._a[i]=B._a[k];
B._a[k]=tmp;
}
}
break;
}
if(j==A.m) break;
if(A._a[i][j]!=(K)0) {
K aii_inv=(K)1/A._a[i][j];
A._a[i][j]=1;
A.Rg++;
B.Rg++;
for(unsigned k=j+1; k<A.n; k++)
A._a[i][k]*=aii_inv;
if(T==INVERSE) {
for(unsigned k=0; k<B.n; k++)
B._a[i][k]*=aii_inv;
}
for(unsigned k=0; k<A.m; k++) {
if(k != i) {
K akj_neg=-A._a[k][j];
for(unsigned l=j; l<A.n; l++)
A._a[k][l]+=A._a[i][l]*akj_neg;
if(T==INVERSE) {
for(unsigned l=0; l<B.n; l++)
B._a[k][l]+=B._a[i][l]*akj_neg;
}
}
}
}
}
if(T==TREPPENNORMALE)
return A;
else {
// Es gibt nur eine Inverse wenn Rg(A)=m ist
if(B.Rg==m)
return B;
else
return null();
}
}
//---------------------------------------------------------------
//------ lineare Gleichungssysteme ------------------------------
template <class K>
Mmn<K> Mmn<K>::solve(void) const {
Mmn<K> A=gauss(TREPPENNORMALE);
Mmn<K> B=Aj(n-1).gauss(TREPPENNORMALE);
// Gibt es eine Loesung???
if(B.Rg != A.Rg)
return null();
else {
K l[B.n][B.n-B.Rg+1];
K a[B.n][A.n];
for(unsigned i=0, j=0; j<B.n && i<B.n; j++) {
if(i>=A.m || A._a[i][j] != (K)1) {
for(unsigned k=0; k<A.n; k++) {
if(k==j)
a[j][k]=(K)-1;
else
a[j][k]=(K)0;
}
}
else {
for(unsigned k=0; k<A.n; k++)
a[j][k]=A._a[i][k];
i++;
}
}
unsigned j=0;
for (unsigned i=0; i<B.n; i++)
l[i][j]=a[i][A.n-1];
j++;
for(unsigned k=0; k<B.n; k++) {
if(a[k][k]==(K)-1) {
for (unsigned i=0; i<B.n; i++)
l[i][j]=a[i][k];
j++;
}
}
return Mmn<K>((K*)l, B.n, B.n-B.Rg+1);
}
}
template <class K>
Mmn<K> Mmn<K>::special_solve(void) const {
Mmn<K> S=solve();
Mmn<K> A(S.m,1);
for(unsigned i=0; i<S.m; i++) {
A._a[i][0]=(K)0;
for(unsigned j=0; j<S.n; j++)
A._a[i][0]+=S._a[i][j];
}
return A;
}
//---------------------------------------------------------------
/****************************************************************/