Jacobi法を用いた行列の固有値の計算

このQ&Aのポイント
  • 25行25列の行列の固有値をJacobi法で計算するプログラムを示す。
  • 行列は対角要素が2、隣は-1、それ以外は0である。
  • 非対角要素の絶対値の最大値が10^-6未満となるまで計算を繰り返す。
回答を見る
  • ベストアンサー

行列について誰か確認してください。

下記問題について自分なりに解答してみたのですが、イマイチあっているのか分かりません。どなたかご査収願います。 問題 『25行25列で、対角要素は全て2、その隣は-1、それ以外は全て0である行列の固有値を全てJacobi(ヤコビ)法で小数点以下6桁まで求め、その固有値と解法のプログラムを示せ。 ※収束基準は非対角要素の絶対値の最大値が10^-6未満となることとせよ。』 以下に上記問題についてのプログラムおよび固有値の計算結果を示します。 プログラミング言語=C言語 #include <math.h> #include <stdlib.h> #include <stdio.h> #define SIZE 25 int main(void) { double a[SIZE][SIZE]; int i, j, k, l; double max; double theta; double x, y; for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { if (i == j - 1 || i == j + 1) a[i][j] = -1; else if (i == j) a[i][j] = 2; else a[i][j] = 0; } } while (1) { max = 0; for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { if (i != j && max < fabs(a[i][j])) { max = fabs(a[i][j]); k = i; l = j; } } } if (max < 1.0e-6) break; theta = (a[k][k] != a[l][l]) ? atan2(-2 * a[k][l], a[k][k] - a[l][l]) / 2 : M_PI / 4; for (i = 0; i < SIZE; i++) { x = a[i][k]; y = a[i][l]; a[i][k] = cos(theta) * x - sin(theta) * y; a[i][l] = sin(theta) * x + cos(theta) * y; } for (j = 0; j < SIZE; j++) { x = a[k][j]; y = a[l][j]; a[k][j] = cos(theta) * x - sin(theta) * y; a[l][j] = sin(theta) * x + cos(theta) * y; } } for (i = 0; i < SIZE; i++) { printf("%lf\n", a[i][i]); } return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

別の方法で固有値を出しましたのでご比較下さい。同じなら大丈夫でしょう。 0.0145822518038919 0.0581163651478958 0.129967514629171 0.229087948693580 0.354032268212688 0.502978503657798 0.673754683518410 0.863870506537689 1.07055365591246 1.29079022591493 1.52136867142488 1.75892663948936 2.00000000000000 2.24107336051065 2.47863132857512 2.70920977408507 2.92944634408754 3.13612949346231 3.32624531648159 3.49702149634220 3.64596773178731 3.77091205130642 3.87003248537083 3.94188363485210 3.98541774819611

matecalorie
質問者

お礼

同じ値となりました。 回答頂き有り難うございました。 大変参考になりました。

関連するQ&A

  • 5×5行列、固有値、固有ベクトル

    5つの値を入力し、それぞれの相対比を求めて行列にして、固有値と固有ベクトルを求めたいのですが、分からないので教えて下さい。下のプログラムは固有値を求めるものです。これは過去の質問にあったプログラムを少し変えてみたのですが、値が出てこないのでどうすればうまく出てくるのか教えて下さい。それと、固有ベクトルを求めるプログラムも教えて下さい。宜しくお願いします。 #include <math.h> #include <stdlib.h> #include <stdio.h> int main(void) { int i, j, k, l; double max,theta,x,y,a[5][5],b[5]; printf("値1: "); scanf("%d",&b[0]); printf("値2: "); scanf("%d",&b[1]); printf("値3: "); scanf("%d",&b[2]); printf("値4: "); scanf("%d",&b[3]); printf("値5: "); scanf("%d",&b[4]); printf("行列\n"); for(j=0;j<5;j++){ for(k=0;k<5;k++){ a[j][k]=b[k]/b[j]; printf("%1.3f ",a[j][k]); } printf("\n"); } while(1){ max=0; for(i=0;i<5;i++){ for(j=0;j<5;j++){ if (i!=j && max<fabs(a[i][j])){ max=fabs(a[i][j]); k=i; l=j; } } } if (max<1.0e-6) break; theta=(a[k][k]!=a[l][l])? atan2(-2*a[k][l],a[k][k]-a[l][l])/2:M_PI/4; for(i=0;i<5;i++){ x=a[i][k]; y = a[i][l]; a[i][k] = cos(theta) * x - sin(theta)*y; a[i][l] = sin(theta) * x + cos(theta)*y; } for (j=0;j<5;j++){ x=a[k][j]; y=a[l][j]; a[k][j]=cos(theta)*x-sin(theta)*y; a[l][j]=sin(theta)*x+cos(theta)*y; } } printf("固有値\n"); for (i=0;i<5;i++){ printf("%1.3f\n",a[i][i]); } return 0; }

  • 配列のエラーに関して

    java言語を用いて,Householder変換を用いた固有値の数値計算に挑戦してみました.しかし,次のようなエラーが発生し上手くいきません.どなたかこの問題を解決するためにお力をかしていただけないでしょうか. ----------エラー内容-------------------------------------------------------------------------------- Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 at Out.Mhouse(House.java:90) at House.main(House.java:10) ---------------------------------------------------------------------------------------------------- //Householder変換 public class House{ public static void main(String[] args){ double[][] A = new double[3][3]; int n = A.length; Out out = new Out(); for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ if(j < n-1){ System.out.print(out.Mhouse(A)[i][j] + " "); }else if (j == n-1) System.out.println(out.Mhouse(A)[i][j]); }; }; }; }; class Out{ double[][] outpro(double[] x){ int n; n = x.length; double[][] A = new double[n][n]; for(int i = 0;i < n;i++ ){ for(int j = 0;j < n;j++){ A[i][j] = x[i] * x[j]; } } return A; }; double[][] Msca(double a,double[][] A){ int n = A.length; for(int i = 0;i < n; i++){ for(int j = 0;j < n;j++){ A[i][j] = a * A[i][j]; } } return A; }; double selfpro(double[] x){ double a = 0; int n = x.length; for(int i = 0;i < n; i++){ a = a + x[i] * x[i]; }; return a; }; double[] minus(double[] x, double[] y){ int n = x.length; double[] z = new double[n]; for(int i = 0;i < n;i++){ z[i] = x[i] - y[i]; }; return z; }; double[][] house_1(double[] x){ int n = x.length; double[][] A = new double[n][n]; for(int i=0;i < n;i++){ for(int j = 0;j < n;j++){ if(i == j){ A[i][j] = 1 - Msca(2/selfpro(x),outpro(x))[i][j]; }else{ A[i][j] = - Msca(2/selfpro(x),outpro(x))[i][j]; }; }; }; return A; }; double[][] house_2(double[] x){ double[][] z = new double[1][1]; z[1][1] = 1 - 2; return z; }; double[][] Mhouse(double[][] A){ int n = A.length; double[][] H = new double[n][n]; for(int i = 0;i < n;i++){ double[] x = new double[n-i]; double[] y = new double[n-i]; double[][][] L = new double[i][n-i][n-i]; for(int j = 0;j < n-i;j++){ x[j] = A[i][i+j]; if(j == 0){ y[j] = 1; }else{ y[j] = 0; }; x[j] = y[j] - x[j]; }; if(i < n-1){ L[i] = house_1(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }else if(i == n-1){ L[i] = house_2(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }; }; double[][] B = new double[n][n]; for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ for(int k = 0;k < n;k++){ B[i][j] = H[i][k] * A[k][j]; }; }; }; return A; }; };

    • ベストアンサー
    • Java
  • LU分解を利用した逆行列のプログラム(Java)

    LU分解を利用した逆行列のプログラムが作れません… というか、作ったのですが実行するとエラーが出てしまいます(´Д`;) どこをどう直せばいいか、もしくはこのようにプログラムした方が効率がよい などのアドバイスどなたか下さい double a[][]={{2,5,4}, {2,3,-1}, {6,9,28}}; int N=a.length; double[][] s=new double[N][N]; for(int k=0; k<a[0].length-1; k++){ for(int i=k+1; i<N; i++){ s[i][k]=a[i][k]/a[k][k]; a[i][k]=s[i][k]; for(int j=k+1; j<N; j++){ a[i][j] -= s[i][k] * a[k][j]; } } } double[][] y=new double[N][N]; double[][] X=new double[N][N]; double[][] e=new double[N][N]; for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ if(i==j){ e[i][j]=1; }else{ e[i][j]=0; } } } for(int i=0;i<N;i++){ y[1][i]=e[1][i]; for(int k=2;k<=N;k++){ for(int j=1;j<=N;j++){ y[k][i]=e[k][i]-s[k][j]*y[j][i]; } } X[N][i]=y[N][i]/a[N][N]; for(int k=N-1;k>=1;k--){ for(int j=k+1;j<=N;j++){ X[k][j]=(y[k][j]-s[k][j]*X[j][i])/a[k][k]; } } } for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ System.out.printf(" %6.5f ", X[i][j] ); } System.out.println(""); }

  • 風の抵抗を考慮した放物運動

    風の抵抗を考慮した放物運動のプログラムを作ったのですが、無限ループが終了しません。どうすればよいでしょうか?以下、プログラムです。 #include<stdio.h> #include<math.h> #define MAX 2 double g=9.8; /*重力加速度*/ double k=0.0; /*抵抗係数*/ void main() { int rhs(double,double*,double*); double x,y[MAX]; double h=0.01; double x_old,y_old[MAX],f[MAX]; double k1[MAX],k2[MAX],k3[MAX],k4[MAX],k_work[MAX]; double z; int i,j; x=0;y[0]=28.3;y[1]=0.0;y[2]=28.3;y[3]=0.0; printf("%f %f %f\n",x,y[1],y[3]); for(i=1; ;i++){ /*ここは無限ループに*/ if(y[3]>0.0){ break; } /*地面に落ちたら計算終了*/ x_old=x; for(j=0;j<MAX;j++)y_old[j]=y[j]; x=i*h; rhs(x_old,y_old,f); for(j=0;j<MAX;j++){k1[j]=h*f[j];k_work[j]=y_old[j]+k1[j]/2.;} rhs(x_old+h/2,k_work,f); for(j=0;j<MAX;j++){k2[j]=h*f[j];k_work[j]=y_old[j]+k2[j]/2.;} rhs(x_old+h/2,k_work,f); for(j=0;j<MAX;j++){k3[j]=h*f[j];k_work[j]=y_old[j]+k3[j];} rhs(x_old+h,k_work,f); for(j=0;j<MAX;j++) k4[j]=h*f[j]; for(j=0;j<MAX;j++) y[j]=y_old[j]+(k1[j]+2*k2[j]+2*k3[j]+k4[j])/6; if(i%1==0)printf("%f %f %f\n",x,y[1],y[3]); } } int rhs(double x,double y[],double f[]) { f[0]=y[1]; f[1]=y[3]; f[2]=-k*pow(f[0]*f[0]+f[1]*f[1],0.5)*f[0]; f[3]=-k*pow(f[0]*f[0]+f[1]*f[1],0.5)*f[1]-g; return 0; }

  • 高校数学の行列の問題の別解がわかりません

    高校数学の行列なのですが、同じ問題で質問を出してますが、こちらは別解が分からなかった ので新しく出しました 問題は 行列(1/5,2/5,p,q)で表さられる平面上の1次変換fが原点を通るある直線l上への正射影となるように実数p,qの値を定め、直線lの方程式を求めよ で解説が直線lの方向ベクトルを↑e=(cosθ,sinθ)とすると,fはl上への正射影だから f;(cosθ、sinθ)→(cosθ,sinθ),(-sinθ,cosθ)→(0,0)となっていたのですが f;(cosθ、sinθ)→(cosθ,sinθ)は分かるのですが、(-sinθ,cosθ)→(0,0)がどういう事なのか 分かりません この後は解説に書いてある事は分かりました 後もうひとつの別解が↑x'=(↑x,↑e)↑e=↑e(↑e,↑x) これを行列を用いて表すと とあるのですが、この最初の式が何を表しているのかが分かりません (続き):(x',y')=(cosθ,sinθ)(cosθ,sinθ)(x,y)=(cos^2θ,cosθsinθ,sinθcosθ,sin^2θ)(x,y) (x',y')=からの式は(cosθ,sinθ)は縦書きでcosθが上,cosθが下です,(cosθ,sinθ)は横書きでcosθが左sinθが右です(x,y)は縦書きでxが上,yが下です,(cos^2θ,cosθsinθ,sinθcosθ,sin^2θ)は行列で左から左上、右上、左下、右下の順です この式も行列で表すと何故あの式になるのか分かりません 第三の別解がまだありまして、直線l上への正射影を考えるから直線l方向の固有値は1,lに垂直な方向の固有値は0とあるのですが、何故固有値が1や0になるのか分かりません 後は(注意)に平面上の点↑xをfで変換した点A↑xは直線l上の点であるからfは不動である よってA^2↑x=A↑xとあるのですが、これも何でこんな事が言えるのか良く分からないです たくさんありますが、どうかよろしくお願いします

  • 行列の固有ベクトルの問題を教えて下さい。

    この問題が分かりません。お願いいたします。 行列A= (cos2θ sin2θ) (sin2θ -cos2θ) がある。(0≦θ<π) 固有値と固有ベクトルを求め、固有ベクトルを図示しなさい。 という問題です。 解いてみると、固有値は1と-1だと分かりました。 しかし、固有ベクトルでつまっています。 例えば固有値1として求めると、 (cos2θ-1)x+sin2θy=0 x=1のとき、y=(1-cos2θ)/sin2θ としてsin2θ≠0のときと=0の時、みたいに場合分けしたのですが、図示出来ませんでした・・・。 固有ベクトルの良い取り方があるのでしょうか? 解答、お願いいたします

  • C++で行列とベクトルの積を求める

    行列とベクトルの掛け算 y=Ax (A(3*3行列以上)とxを適当に初期化) を作成せよ これが分からないんですが誰か分かる人いませんか?下は行列の和と積をそれぞれ求めてるんですが、こんな感じになりそうなんですよね #include<iostream> using namespace std; int main() { double A[3][3]={{1,1,6},{5,3,2},{2,2,2}}; double B[3][3]={{4,1,3},{2,4,3},{5,9,2}}; double temp; int i,j,k; for(i=0;i<3;i++){ for(k=0;k<3;k++){ } } for(i=0;i<3;i++){ for(k=0;k<3;k++){ } } cout<<"和:A+B="<< '\n'; for(i=0;i<3;i++){ cout<<" { "; for(j=0;j<3;j++){ cout<< (A[i][j]+B[i][j]); if(j!=2) cout<<" , "; } cout<< " }" << '\n'; } cout<< '\n'; cout<<"積:A*B="<< '\n'; for(i=0;i<3;i++){ cout<<" { "; for(j=0;j<3;j++){ temp=0.0; for(k=0;k<3;k++) temp += A[i][k]*B[k][j]; cout<< temp; if(j!=2) cout<< " , "; } cout<< " }" << '\n'; } return 0; }

  • 行列のノルム

    以下、xはn次元ベクトル、A=(a(i,j))はn×n行列とします。 ■||x||_2 = √{Σ_[j=1~n](x_j)^2} (ユークリッドノルム) ※x_jは、xの第j成分です。 このノルムを採用したとき、行列Aのノルムは以下のように定義することが出来る。 ・||A||_2 = MAX_[x]{||Ax||_2/||x||_2} この具体的な表現は以下で与えられる、らしいのですが…。 ・||A||_2 = MAX_[k]{√(μ_k)} (μ_kは、BをAの転置行列として、BAの固有値。) 本を読んでも、「簡単に導出できるので試みられたい。」とかしか書かれておらず、困っています。どうやって導出するのでしょうか?僕には簡単に導出できません。 また、 ■||x||_∞ = MAX_[k]{|x_k|}  ※x_kは、ベクトルxの第k成分。 このノルムを採用したとき、行列Aのノルムを ・||A||_∞ = MAX_[x]{||Ax||_∞/||x||_∞} と定義できて、この具体的な表現は、 ・MAX_[i]{Σ_[j=1~n]|a(i,j)|} で与えられるらしいのですが、本を読んでも、これも証明が省かれています。 ||A||_1についてはきちんと証明が載っているのですが…。 どちらか片方ずつでも、おねがいします。

  • 交叉について

    c言語を使い始めて、TSPについて勉強中で、遺伝的アルゴリズムの交叉(順序交叉)について以下のプログラムを作ってみたのですが、凄く遅いです。答えはきちんと出るのですが、循環交叉を取り入れたプログラムは5000ループでも1秒弱で出るのに対して20秒近くかかってしまいます。ループに無駄が多そうなのですが思いつきません。ヒントでも宜しいのでご教授下さい。 順序交叉とは、例えば x[i] = 3,4,5,2,1とy[i] = 4,3,5,1,2(i = 0~)という数字が与えられたときtargetを2とすると x[i] = 3,4, y[i] = 4,3まではそのまま受け継ぎ、3以降は相手方の数字を左から順番に使われていないものを取り入れていくものです。この場合だと、x[i] = 3,4,5,1,2 y[i] = 4,3,5,2,1となります。 #define a 5 int main(void) {    int x[a] = {3, 4, 5, 2, 1}, y[a] = {4, 3, 5, 1, 2};    int target, i, j, k, l;    int x2[a], y2[a];    srand((unsigned)time(NULL));    target = rand () % a;    for (i = 0; i < target; i++) {       x2[i] = x[i];       y2[i] = y[i];    }    for (i = target; i < a; i++) {       x2[i] = 0;       y2[i] = 0;    }    j = 0;    k = 0;    while (k != a - target) {       for (i = 0; i < target + k; i++) {          for (l = 0; l < target + k; l++) {             if (x2[l] == y[j])                j++;          }       }       if (x2[target + k] != y[j]) {          x2[target + k] = y[j];          k++;          j++;       }       else          j++;    }    yについても同様の作業です }

  • 行列の積を関数を使って求める・・?

    2つの行列の行と列を入力し、積を計算するプログラムを関数を使って書きたいのですが、上手く行きません。どこをどのように直したらよいか教えてください!お願いします!! 以下が私が書いたプログラムです。 #include<stdio.h> #define NUMBER 10 int first(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; do{ printf("2つの行列の行と列を入力してください\n"); scanf("%d", &x1); scanf("%d", &x2); scanf("%d", &y1); scanf("%d", &y2); if(x1 != y2){ printf("行列の積は計算できません\n"); } }while(x1 != y2); printf("行列Aの要素を入力してください\n"); for(i=0; i<x1; i++){ for(j=0; j<x2; j++) scanf("%d", &a[i][j]); } printf("行列Bの要素を入力してください\n"); for(j=0; j<y1; j++){ for(k=0; k<y2; k++) scanf("%d", &b[j][k]); } } int second(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; for(i=0; i<x1; i++){ for(k=0; k<y2; k++){ for(j=0; j<x2; j++) c[i][k] = c[i][k] + a[i][j]*b[j][k]; } } for(i=0; i<x2; i++){ for(k=0; k<y2; k++) printf("%3d", c[i][k]); printf("\n"); } } int main(void) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; printf("行列の積を計算します\n %d\n", first(x1,x2,y1,y2,i,j,k)); printf("行列Aと行Bの積は\n %3d",second(x1,x2,y1,y2,i,j,k)); }