Javaで行列式計算(余因子展開)

行列式を手で簡単に解く方法として、サラスの方法があります。
もちろんプログラムでもサラスの方法は利用することはできるのですが、この方法では4次以上の行列に対して行列式を求めることができません。そこで、4次以上の行列の行列式を求めるために、余因子展開を用いたJavaプログラムのサンプルを紹介します。

(なお、確実にテストを行ったわけではないので、自己責任の範囲内で利用してください。バグの報告はコメントにお願いします。)

public class Sample {
	private static interface ArrayAccess {
		
		int size();
		double get(int r, int c);
	}
	
	private static class WrapEntity implements ArrayAccess {

		private ArrayAccess array;
		private int row;
		private int col;
		private int size;
		
		public WrapEntity(ArrayAccess a, int r, int c){
			this.array = a;
			this.row = r;
			this.col = c;
			this.size = a.size()-1;
		}
		
		public double get(int r, int c) {
			r = r>=row ? r+1: r;
			c = c>=col ? c+1: c;
			return array.get(r, c);
		}

		public int size() {
			return size;
		}
		
	}
	
	private static class Entity implements ArrayAccess {
		
		private double[][] array;
		private int row;		
		private int col;
		private int size;
		
		public Entity(double[][] a, int r, int c){
			this.array = a;
			this.row = r;
			this.col = c;
			this.size = a.length-1;
		}
		
		public int size(){
			return size;
		}
		
		public double get(int r, int c){
			r = r>=row ? r+1: r;
			c = c>=col ? c+1: c;
			return array[r][c];
		}
	}
	
	private static double sub(ArrayAccess array){
		if(array.size()==1){
			return array.get(0, 0);
		}
		if(array.size()==2){
			return array.get(0, 0)*array.get(1, 1)
					-array.get(0, 1)*array.get(1, 0);
		}
		// 行列式の計算
		double det = 0;
		final int length = array.size();
		for(int i=0;i<length;i++){
			double v = array.get(0, i);
			if(v!=0){
				double d = v*sub(new WrapEntity(array,0,i));
				det += i%2==0? d: -d;
			}
		}
		return det;
	}
	
	public static double cofactor(double[][] array){
		// 引数チェック
		if(array==null){
			throw new NullPointerException();
		}
		final int length = array[0].length;
		for(int i=0; i<array.length; i++){
			if(array[i].length!=length)
				throw new IllegalArgumentException();
		}

		// 行列式の計算
		double det = 0;
		for(int i=0;i<length;i++){
			double v = array[0][i];
			if(v!=0){
				double d = v*sub(new Entity(array,0,i));
				det += i%2==0? d: -d;
			}
		}
		return det;
	}

// サンプル用メインメソッド
public static void main(String[] args){ double[][] array = {{1,2,3},{4,5,6},{7,8,9}}; System.out.println(cofactor(array)); } }
ここで、簡単にソースの説明を。
前半のArrayAccessインターフェース、WrapEntityクラス、Entityクラスは、配列の配列を余因子行列のように見せるためのエンティティクラスです。このクラスを利用しない場合は、配列の内容を毎回コピーする必要があるので、処理速度を高めるために導入しています。

後半のsubメソッド、cofactorメソッドが行列式を計算するメソッドになります。
2つのメソッドはほぼ同じ処理をしていますが、cofactorでは引数チェックを行っている点が異なります。また、subメソッドでは余因子展開を再帰を用いて計算しています。

もう少し考えればもっと効率は良くなるかと思いますが、とりあえずは処理の流れが理解しやすい今の状態を公開することにします。

前へ

Apache Commonsを使って行列計算

次へ

VelocityでResourceNotFoundExceptionが発生する場合の対処法