C#で行列式を計算するコードを書いてみた
ネットで見つけた順列を生成するC#のコードを参考にして、行列式を計算するコードを書いてみた。
2行2列で要素の値が0,1,2のどれかで行列式の値が1のものを表示するプログラム。2行2列で要素の値が0,1,2のどれかである行列は重複ありの順列を使って生成させてみた。
>|cs|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
static class Extensions
{
public static IEnumerable<IEnumerable<T>> Perm<T>(this IEnumerable<T> items, int? k = null)
{
if (k == null)
k = items.Count();
if (k == 0)
{
yield return Enumerable.Empty<T>();
}
else
{
foreach (var x in items)
{
var xs = items.ToList();
xs.Remove(x);
foreach (var c in Perm(xs,k - 1)){
var newelem = (new T {x}).Concat(c).ToArray();
yield return newelem;
}
}
}
}
public static IEnumerable<IEnumerable<T>> RepeatedPerm<T>(this IEnumerable<T> items, int? k = null)
{
if (k == null)
k = items.Count();
if (k == 0)
{
yield return Enumerable.Empty<T>();
}
else
{
foreach (var x in items)
{
var xs = items.ToList();
foreach (var c in RepeatedPerm(xs,k - 1)){
var newelem = (new T {x}).Concat(c).ToArray();
yield return newelem;
}
}
}
}
}
public class Matrix
{
int dim;
public int[,] elements;
public Matrix(int order)
{
dim = order;
elements = new int[dim,dim];
}
public Matrix(int order,int[,] elm)
{
dim = order;
elements = elm;
}
public static Matrix operator +(Matrix a, Matrix b)
{
int[,] elm;
int n, i, j;
n = a.dim;
elm = new int[n,n];
for(i=0;i<n;i++){
for(j=0;j<n;j++){
elm[i,j] = a.elements[i,j] + b.elements[i,j];
}
}
return new Matrix(n,elm);
}
public static Matrix operator -(Matrix a, Matrix b)
{
int[,] elm;
int n, i, j;
n = a.dim;
elm = new int[n,n];
for(i=0;i<n;i++){
for(j=0;j<n;j++){
elm[i,j] = a.elements[i,j] - b.elements[i,j];
}
}
return new Matrix(n,elm);
}
public static Matrix operator *(Matrix a, Matrix b)
{
int[,] elm;
int n, i, j, k, sum;
n = a.dim;
elm = new int[n,n];
for(i=0;i<n;i++){
for(j=0;j<n;j++){
sum = 0;
for(k=0;k<n;k++){
sum += a.elements[i,k] * b.elements[k,j];
}
elm[i,j] = sum;
}
}
return new Matrix(n,elm);
}
public void WriteLine()
{
int i, j;
for(i=0;i<dim;i++){
for(j=0;j<dim;j++){
Console.Write(" {0,6:d0}",elements[i, j]);
}
Console.WriteLine();
}
}
//public static int signature(int src, int ar)
public static int signature(int src, IEnumerable<int> plist)
{
int cnt = 0, swp, i, j;
int ar = plist.ToArray();
int br = new int[ar.Length];
for(i=0;i<ar.Length;i++){
br[i] = ar[i];
}
for(i=0;i<src.Length;i++){
if ( src[i] != br[i] ){
for(j=i;j<src.Length;j++){
if ( br[j] == src[i] ){
swp = br[i];
br[i] = src[i];
br[j] = swp;
cnt++;
}
}
}
}
return cnt%2==0?1:(-1);
}
public int Determinant()
{
int src;
int sgn, sum, pro, i, j;
src = new int[dim];
for(i=0;i<dim;i++) src[i]=i;
sum = 0;
var perm = src.Perm();
foreach( var plist in perm )
{
pro = 1;
j = 0;
foreach( var p in plist )
{
pro *= elements[j,p];
j++;
}
sgn = signature(src,plist);
pro *= sgn;
sum += pro;
}
//Console.WriteLine("----- << det >> ----");
//Console.WriteLine("sum = {0}",sum);
return sum;
}
public Matrix Small(int n, int m)
{
int[,] small;
int i,j, c_row, c_col;
Console.WriteLine("--- small ---");
small = new int[dim-1,dim-1];
c_row = 0;
for ( i=0; i< dim; i++ ){
if ( i != n ){
c_col = 0;
for ( j=0; j< dim; j++ ){
if ( j != m ){
small[c_row,c_col] = elements[i,j];
//Console.Write(" {0}",small[c_row,c_col]);
c_col++;
}
}
//Console.WriteLine();
c_row++;
}
}
//Console.WriteLine("--------");
for ( i=0; i< dim -1; i++ ){
for ( j=0; j< dim -1; j++ ){
//Console.Write(" {0}",small[i,j]);
}
//Console.WriteLine();
}
Matrix a = new Matrix(dim-1,small);
return a;
}
public int cofactor(int n, int m)
{
int[,] small;
int sgn,det,i,j, c_row, c_col;
if ( dim < 2 ){
return 0;
}
//Console.WriteLine("--- cofactor ---");
small = new int[dim-1,dim-1];
c_row = 0;
for ( i=0; i< dim; i++ ){
if ( i != n ){
c_col = 0;
for ( j=0; j< dim; j++ ){
if ( j != m ){
small[c_row,c_col] = elements[i,j];
//Console.Write(" {0}",small[c_row,c_col]);
c_col++;
}
}
//Console.WriteLine();
c_row++;
}
}
//Console.WriteLine("--------");
for ( i=0; i< dim -1; i++ ){
for ( j=0; j< dim -1; j++ ){
//Console.Write(" {0}",small[i,j]);
}
//Console.WriteLine();
}
Matrix a = new Matrix(dim-1,small);
det = a.Determinant();
sgn = (n+m)%2==0?1:(-1);
//Console.WriteLine("< {0} : {1} > det = {2} sgn={3}",n,m,det,sgn);
return sgn*det;
}
public Matrix Cofactorize()
{
int[,] inv = new int[dim,dim];
int i,j;
for(i = 0; i < dim; i++) {
for(j = 0; j < dim; j++)
{
inv[i,j] = cofactor(j,i);
}
}
return new Matrix(dim,inv);
}
public int Rank()
{
Matrix s;
int max =0, rk, det, i, j;
if ( dim == 1 ){
if ( elements[0,0] == 0 ){
return 0;
}
else {
return 1;
}
}
det = Determinant();
Console.WriteLine("det = {0}",det);
if ( det != 0 ){
return dim;
}
else{
for(i=0;i<dim;i++){
for(j=0;j<dim;j++){
s = Small(i,j);
Console.WriteLine("< {0} : {1} > ",i,j);
s.WriteLine();
//det = s.Determinant();
//Console.WriteLine("det = {0}",det);
rk = s.Rank();
if ( rk > max ){
max = rk;
}
}
}
}
Console.WriteLine("max = {0}",max);
return max;
}
public void Unit()
{
for(int i = 0; i < dim; i++) {
elements[i,i] = 1;
}
}
public void ZeroClear()
{
int i,j;
for(i = 0; i < dim; i++) {
for(j = 0; j < dim; j++)
{
elements[i,j] = 0;
}
}
}
public void Jordan()
{
int i,j;
for(i = 0; i < dim; i++) {
for(j = 0; j < dim; j++)
{
if ( j == (i+1) ){
elements[i,j] = 1;
}
else {
elements[i,j] = 0;
}
}
}
}
}
class Program
{
static void Main(string args)
{
int order = 2;
int i, j;
int cnt = 0;
Matrix A;
int[,] matrix = new int[order, order];
var source = new int { 0, 1, 2, };
//var source = new int { -1, 0, 1 };
//var source = new int { 1, 2, };
var duplex = source.RepeatedPerm( order * order );
foreach( var dlist in duplex )
{
i = 0;
j = 0;
foreach( var d in dlist )
{
if ( j > 0 && j % order == 0 )
{
i++;
j=0;
}
matrix[i,j] = d;
j++;
}
A = new Matrix(order,matrix);
if ( A.Determinant() == 1 ){
Console.WriteLine("[{0}]",++cnt);
A.WriteLine();
Console.WriteLine();
}
}
Console.WriteLine("--- det 1 matrix :{0} / case num = {1} ---",cnt,duplex.Count());
}
}
||<
◎実行例
2行2列で要素の値が0,1,2のどれかで行列式の値が1のものを表示する。
PS >.\matrix.exe
[1]
1 0
0 1
[2]
1 0
1 1
[3]
1 0
2 1
[4]
1 1
0 1
[5]
1 1
1 2
[6]
1 2
0 1
[7]
2 1
1 1
--- det 1 matrix :7 / case num = 81 ---