#include #include #include #include "fkn.h" #include "fknDlg.h" #include "complex.h" #include "spars.h" #define MAXITER 1000000 #define KLUDGE #define nrm(X) sqrt(Re(ConjDot(X,X))) CComplexEntry::CComplexEntry() { next=NULL; x=0; c=0; } CBigComplexLinProb::CBigComplexLinProb() { n=0; } CBigComplexLinProb::~CBigComplexLinProb() { if (n==0) return; int i; CComplexEntry *uo,*ui; free(b); free(P); free(R); free(V); free(U); free(Z); free(uu); free(vv); for(i=0;inext; delete uo; } while(ui!=NULL); } free(M); if (bNewton) { for(i=0;inext; delete uo; } while(ui!=NULL); } free(Mh); for(i=0;inext; delete uo; } while(ui!=NULL); } free(Ma); for(i=0;inext; delete uo; } while(ui!=NULL); } free(Ms); } } int CBigComplexLinProb::Create(int d, int bw, int nodes) { int i; bdw=bw; NumNodes=nodes; b=(CComplex *)calloc(d,sizeof(CComplex)); V=(CComplex *)calloc(d,sizeof(CComplex)); P=(CComplex *)calloc(d,sizeof(CComplex)); R=(CComplex *)calloc(d,sizeof(CComplex)); U=(CComplex *)calloc(d,sizeof(CComplex)); Z=(CComplex *)calloc(d,sizeof(CComplex)); uu=(CComplex *)calloc(d,sizeof(CComplex)); vv=(CComplex *)calloc(d,sizeof(CComplex)); n=d; M=(CComplexEntry **)calloc(d,sizeof(CComplexEntry *)); for(i=0;ic = i; } bNewton=FALSE; return 1; } void CBigComplexLinProb::Put(CComplex v, int p, int q, int k) { CComplexEntry *e,*l; int i; if(q0) && (bNewton==FALSE)) { bNewton=TRUE; Mh=(CComplexEntry **)calloc(n,sizeof(CComplexEntry *)); for(i=0;ic = i; } Ma=(CComplexEntry **)calloc(n,sizeof(CComplexEntry *)); for(i=0;ic = i; } Ms=(CComplexEntry **)calloc(n,sizeof(CComplexEntry *)); for(i=0;ic = i; } } switch(k) { case 1: e=Mh[p]; break; case 2: e=Ms[p]; break; case 3: e=Ma[p]; break; default: e=M[p]; break; } while((e->c < q) && (e->next != NULL)) { l=e; e=e->next; } if(e->c == q){ e->x=v; return; } CComplexEntry *m = new CComplexEntry; if((e->next == NULL) && (q > e->c)){ e->next = m; m->c = q; m->x = v; } else{ l->next=m; m->next=e; m->c=q; m->x=v; } return; } CComplex CBigComplexLinProb::Get(int p, int q, int k) { CComplexEntry *e; BOOL flip=FALSE; if(qc < q) && (e->next != NULL)) e=e->next; if(e->c == q) { if(flip) { if(k==1) return conj(e->x); // case where matrix is hermitian... if(k==3) return -conj(e->x); // case where matrix is anti-hermitian... } return e->x; } // if no entry in the list, this entry must be zero... return CComplex(0,0); } void CBigComplexLinProb::AddTo(CComplex v, int p, int q) { Put(Get(p,q)+v,p,q); } void CBigComplexLinProb::MultA(CComplex *X, CComplex *Y, int k) { int i; CComplexEntry *e; for(i=0;ix*X[i]); e=Mh[i]->next; break; case 2: Y[i]+=(Ms[i]->x*X[i]); e=Ms[i]->next; break; case 3: Y[i]+=(Ma[i]->x*X[i]); e=Ma[i]->next; break; default: Y[i]+=(M[i]->x*X[i]); e=M[i]->next; break; } while(e!=NULL) { Y[i]+=(e->x*X[e->c]); if (k==1) Y[e->c]+=(conj(e->x)*X[i]); // case in which the matrix is hermitian else if (k==3) Y[e->c]+=(-conj(e->x)*X[i]); // case in which the matrix is antihermitian else Y[e->c]+=(e->x*X[i]); // case in which the matrix is complex-symmetric e=e->next; } } } void CBigComplexLinProb::MultConjA(CComplex *X, CComplex *Y, int k) { int i; CComplexEntry *e; for(i=0;ix.Conj()*X[i]); e=Mh[i]->next; break; case 2: Y[i]+=(Ms[i]->x.Conj()*X[i]); e=Ms[i]->next; break; case 3: Y[i]+=(Ma[i]->x.Conj()*X[i]); e=Ma[i]->next; break; default: Y[i]+=(M[i]->x.Conj()*X[i]); e=M[i]->next; break; } while(e!=NULL) { Y[i]+=(e->x.Conj()*X[e->c]); if (k==1) Y[e->c]+=(e->x*X[i]); // case in which the matrix is hermitian if (k==3) Y[e->c]+=(-e->x*X[i]); // case in which the matrix is antihermitian else Y[e->c]+=(e->x.Conj()*X[i]); // case in which the matrix is complex-symmetric e=e->next; } } } void CBigComplexLinProb::MultAPPA(CComplex *X, CComplex *Y) { int i; MultA(X,Z); MultPC(Z,Y); for(i=0;ix; return; // SSOR preconditioner CComplex c; CComplexEntry *e; c= LAMBDA*(2.-LAMBDA); for(i=0;ix; e=M[i]->next; while(e!=NULL) { Y[e->c] -= e->x * Y[i] * LAMBDA; e=e->next; } } for(i=0;ix; // invert Upper Triangle for(i=n-1;i>=0;i--){ e=M[i]->next; while(e!=NULL) { Y[i] -= e->x * Y[e->c] * LAMBDA; e=e->next; } Y[i]/= M[i]->x; } } void CBigComplexLinProb::SetValue(int i, CComplex x) { int k,fst,lst; CComplex z; if(bdw==0){ fst=0; lst=n; } else{ fst=i-bdw; if (fst<0) fst=0; lst=i+bdw; if (lst>NumNodes) lst=NumNodes; } for(k=fst;kx=0; e=e->next; } while(e!=NULL); } if (!bNewton) return; for(i=0;ix=0; e=e->next; } while(e!=NULL); } for(i=0;ix=0; e=e->next; } while(e!=NULL); } for(i=0;ix=0; e=e->next; } while(e!=NULL); } } void CBigComplexLinProb::AntiPeriodicity(int i, int j) { int k,fst,lst,h; CComplex v1,v2,c; #ifdef KLUDGE int tmpbdw=bdw; bdw=0; #endif if (jNumNodes-1) lst=NumNodes-1; } // contribution to A0 matrix for(k=fst;kNumNodes-1) lst=NumNodes-1; } for(k=fst;kx.re==0) && (M[i]->x.im==0)){ fprintf(stderr,"singular flag tripped."); return 0; } // Operate on RHS to scale for squared problem MultPC(b,Z); for(i=0;im_prog1.SetPos(5*prg1); TheView->SetDlgItemText(IDC_FRAME1,"BiConjugate Gradient Solver"); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); // form initial search direction; MultPC(R,Z); for(i=0;iprg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } } while(er>Precision); return 1; } // BiCGSTAB for solving N-R iterations int CBigComplexLinProb::BiCGSTAB(int flag) { double er,normb; CComplex om,alf,rho1,rho2,bta; CComplex *P2,*R2,*Z2,*t; int i,j,k; CString out; P2=(CComplex *)calloc(n,sizeof(CComplex)); Z2=(CComplex *)calloc(n,sizeof(CComplex)); R2=(CComplex *)calloc(n,sizeof(CComplex)); t =(CComplex *)calloc(n,sizeof(CComplex)); // initialize progress bar; TheView->m_prog1.SetPos(0); int prg1=0; int prg2; TheView->SetDlgItemText(IDC_FRAME1,"BiCGSTAB Solver"); if (flag==FALSE) for(i=0;iSetDlgItemText(IDC_FRAME1,out); } prg2=(int) (20.*log10(er)/(log10(Precision))); if(prg2>prg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } if (erSetDlgItemText(IDC_FRAME1,"Initializing Solver"); if (PCGSQStart()==0) return 0; } // call the complex-symmetric solver return PBCGSolve(2); }