Matrix.cpp
#include "Matrix.h"
#include "Vector.h"
using namespace Robotics;
using namespace System;
using namespace System::Diagnostics;
Matrix::Matrix( int row, int column )
{
SecureDomain( row );
for( int m=0; m<row; m++ )
{
m_rowVectors[ m ] = gcnew Vector( column );
}
#ifdef _DEBUG
for( int m=0; m<Row; m++ )
{
Debug::Assert(
m_rowVectors[ m ]->IsZeroVector(),
"零行列に初期化されている"
);
}
#endif
}
Matrix::Matrix( Matrix^ other )
{
SecureDomain( other->Row );
for( int m=0; m < other->Row; m++ )
{
m_rowVectors[ m ] = gcnew Vector( other->m_rowVectors[ m ] );
}
}
void Matrix::SecureDomain( int row )
{
Debug::Assert( 1 <= row , "行数は1以上である" );
m_rowVectors = gcnew array< Vector^ >( row );
}
void Matrix::SetSize( int row, int column )
{
Debug::Assert( ( row != Row ) || ( column != Column ), "行数または列数は変更される" );
delete m_rowVectors;
SecureDomain( row );
for( int m=0; m<row; m++ )
{
m_rowVectors[ m ] = gcnew Vector( column );
}
}
Vector^ Matrix::default::get( int index )
{
Debug::Assert( ( 0 <= index ) && ( index <= Row ), "添え字は行数の範囲内である" );
return m_rowVectors[ index - 1 ];
}
int Matrix::Column::get()
{
return m_rowVectors[ 0 ]->Dimension;
}
Matrix^ Matrix::operator+=( Matrix^ obj )
{
Debug::Assert( IsEqualSize( obj ), "引数の行列と大きさは等しい" );
for( int m=0; m<Row; m++ )
{
m_rowVectors[ m ] += obj->m_rowVectors[ m ];
}
return this;
}
Matrix^ Matrix::operator-=( Matrix^ obj )
{
Debug::Assert( IsEqualSize( obj ), "引数の行列と大きさは等しい" );
for( int m=0; m<Row; m++ )
{
m_rowVectors[ m ] -= obj->m_rowVectors[ m ];
}
return this;
}
Matrix^ Matrix::operator*=( double val )
{
for(int m=0; m<Row; m++ )
{
m_rowVectors[ m ] *= val;
}
return this;
}
Matrix^ Matrix::operator*=( Matrix^ obj )
{
Matrix^ result = this * obj;
for( int m=0; m<Row; m++ )
{
m_rowVectors[ m ] = gcnew Vector( result->m_rowVectors[ m ] );
}
return this;
}
Matrix^ Matrix::operator+( Matrix^ left, Matrix^ right )
{
Matrix^ result = gcnew Matrix( left );
result += right;
return result;
}
Matrix^ Matrix::operator-( Matrix^ left, Matrix^ right )
{
Matrix^ result = gcnew Matrix( left );
result -= right;
return result;
}
Vector^ Matrix::operator*( Matrix^ matrix, Vector^ vector )
{
Debug::Assert(
matrix->Column == vector->Dimension,
"行列の列数とベクトルの次数は等しい"
);
Vector^ result = gcnew Vector( matrix->Row );
for( int m=1; m<=matrix->Row; m++ )
{
double sum = 0.0;
for( int n=1; n<=matrix->Column; n++ )
{
sum += matrix[ m ][ n ] * vector[ n ];
}
result[ m ] = sum;
}
result->RemoveErrorComponent();
return result;
}
Vector^ Matrix::operator*( Vector^ vector, Matrix^ matrix )
{
Debug::Assert(
vector->Dimension == matrix->Column,
"ベクトルの次数と行列の列数は等しい"
);
Vector^ result = gcnew Vector( matrix->Column );
for( int n=1; n<=matrix->Column; n++ )
{
double sum = 0.0;
for( int m=1; m<=matrix->Row; m++ )
{
sum += vector[ m ] * matrix[ m ][ n ];
}
result[ n ] = sum;
}
result->RemoveErrorComponent();
return result;
}
Matrix^ Matrix::operator*( Matrix^ left, Matrix^ right )
{
Debug::Assert(
left->Column == right->Row,
"行列left の列数と行列right の行数は等しい"
);
Matrix^ result = gcnew Matrix( left->Row, right->Column );
for( int m=1; m <= left->Row; m++ )
{
for( int r=1; r <= right->Column; r++ )
{
double sum = 0.0;
for( int n=1; n <= left->Column; n++ )
{
sum += left[ m ][ n ] * right[ n ][ r ];
}
result[ m ][ r ] = sum;
}
}
result->RemoveErrorComponent();
return result;
}
bool Matrix::operator==( Matrix^ left, Matrix^ right )
{
return left->Equals( right, Double::Epsilon );
}
bool Matrix::operator!=( Matrix^ left, Matrix^ right )
{
return !left->Equals( right, Double::Epsilon );
}
bool Matrix::Equals( Matrix^ obj )
{
return Equals( obj, Double::Epsilon );
}
bool Matrix::Equals( Matrix^ obj, double precision )
{
if( safe_cast< System::Object^ >( obj ) == nullptr ) return false;
Debug::Assert( IsEqualSize( obj ), "引数の行列と大きさは等しい" );
for( int m=0; m<Row; m++ )
{
if( !m_rowVectors[ m ]->Equals( obj->m_rowVectors[ m ], precision ) )
{
return false;
}
}
return true;
}
void Matrix::ZeroMatrix()
{
for( int m=0; m<Row; m++ )
{
m_rowVectors[ m ]->ZeroVector();
}
}
void Matrix::UnitMatrix()
{
Debug::Assert( IsSquareMatrix(), "正方行列である" );
for( int n=1; n<=Column; n++ )
{
for( int m=1; m<=Row; m++ )
{
this[ m ][ n ] = ( m == n )? 1.0 : 0.0;
}
}
}
Matrix^ Matrix::TransposedMatrix()
{
Matrix^ result = gcnew Matrix( Column, Row );
for( int n=1; n<=Column; n++ )
{
for( int m=1; m<=Row; m++ )
{
result[ n ][ m ] = this[ m ][ n ];
}
}
return result;
}
bool Matrix::InverseMatrix( Matrix^% result )
{
Debug::Assert( IsSquareMatrix(), "正方行列である" );
Matrix^ matrix = gcnew Matrix( this );
array< int >^ informationToChangeRow;
if( !matrix->LuDecomposition( informationToChangeRow ) )
{
return false;
}
result = gcnew Matrix( Row, Column );
for( int n=1; n<=Row; n++ )
{
for( int m=1; m<=Row; m++ )
{
const int row = informationToChangeRow[ m ];
double component = ( row == n )? 1.0 : 0.0;
for( int i=1; i<m; i++ )
{
component -= matrix[ row ][ i ] * result[ i ][ n ];
}
result[ m ][ n ] = component;
}
for( int m=Row; m>=1; m-- )
{
const int row = informationToChangeRow[ m ];
double component = result[ m ][ n ];
for( int i=m+1; i<=Row; i++ )
{
component -= matrix[ row ][ i ] * result[ i ][ n ];
}
result[ m ][ n ] = component / matrix[ row ][ m ];
}
}
return true;
}
bool Matrix::LuDecomposition( array< int >^% informationToChangeRow )
{
Debug::Assert( informationToChangeRow == nullptr, "結果を格納する引数は 生成されていないものである" );
Debug::Assert( IsSquareMatrix(), "正方行列である" );
informationToChangeRow = gcnew array< int >( Row + 1 );
for( int n=1; n<=Row; n++ )
{
informationToChangeRow[ n ] = n;
}
array< double >^ maxAbsolutes = GetComponentWithMaximumAbsoluteValue();
for( int n=1; n<=Row; n++ )
{
if( maxAbsolutes[ n ] == 0.0 )
{
return false;
}
}
for( int n=1; n<=Row; n++ )
{
int maxRow = Row;
double max = Double::MinValue;
for( int m=n; m<=Row; m++ )
{
const int row = informationToChangeRow[ m ];
double component = maxAbsolutes[ row ] * Math::Abs( this[ row ][ n ] );
if( max < component )
{
max = component;
maxRow = m;
}
}
const int currentRow = informationToChangeRow[ maxRow ];
if( maxRow != n )
{
informationToChangeRow[ maxRow ] = informationToChangeRow[ n ];
informationToChangeRow[ n ] = currentRow;
}
const double diagonalComponent = this[ currentRow ][ n ];
if( Math::Abs( diagonalComponent ) < Double::Epsilon )
{
return false;
}
for( int m=n+1; m<=Row; m++ )
{
const int row = informationToChangeRow[ m ];
this[ row ][ n ] /= diagonalComponent;
for( maxRow=n+1; maxRow<=Row; maxRow++ )
{
this[ row ][ maxRow ] -= this[ row ][ n ] * this[ currentRow ][ maxRow ];
}
}
}
return true;
}
array< double >^ Matrix::GetComponentWithMaximumAbsoluteValue()
{
array< double >^ result = gcnew array< double >( Row + 1 );
for( int n=1; n<=Row; n++ )
{
double max = 0.0;
for( int m=1; m<=Row; m++ )
{
const double absolute = Math::Abs( this[ n ][ m ] );
if( max < absolute )
{
max = absolute;
}
}
result[ n ] = ( max == 0.0 )? 0.0 : 1.0 / max;
}
return result;
}
bool Matrix::IsEqualSize( Matrix^ obj )
{
return ( Row == obj->Row ) && ( Column == obj->Column);
}
bool Matrix::IsSquareMatrix()
{
return Row == Column;
}
bool Matrix::IsOrthogonalMatrix( double precision )
{
Debug::Assert( IsSquareMatrix(), "正方行列である" );
Matrix^ matrix = TransposedMatrix();
matrix *= this;
return matrix->IsUnitMatrix( precision );
}
bool Matrix::IsUnitMatrix( double precision )
{
Debug::Assert( IsSquareMatrix(), "正方行列である" );
Matrix^ compare = gcnew Matrix( Row, Column );
compare->UnitMatrix();
return Equals( compare, precision );
}
bool Matrix::IsZeroMatrix()
{
Matrix^ compare = gcnew Matrix( Row, Column );
#ifdef _DEBUG
for( int m=1; m<=compare->Row; m++ )
{
Debug::Assert(
compare[ m ]->IsZeroVector(),
"零行列に初期化されている"
);
}
#endif
return ( this == compare );
}
void Matrix::RemoveErrorComponent()
{
double maxOfAbsoluteValue = 0.0;
for( int m=1; m<=Row; m++ )
{
for( int n=1; n<Column; n++ )
{
double compare = Math::Abs( this[ m ][ n ] );
if( maxOfAbsoluteValue < compare )
{
maxOfAbsoluteValue = compare;
}
}
}
if( Double::Epsilon < maxOfAbsoluteValue )
{
for( int m=1; m<=Row; m++ )
{
for( int n=1; n<Column; n++ )
{
if( ( Math::Abs( this[ m ][ n ] ) / maxOfAbsoluteValue ) < Tolerance )
{
this[ m ][ n ] = 0.0;
}
}
}
}
}
System::String^ Matrix::ToString()
{
String^ result;
for each( Vector^ vector in m_rowVectors )
{
result += vector->ToString() + Environment::NewLine;
}
return result;
}