선형 대수학
Colin Fahey
1. 소프트웨어
LinearAlgebra.zip
선형 대수학 소스 코드를 (C#)
19910 bytes
MD5: 11d8c8035cac30ba543e5e0b72ee9767
2. 소개
이 문서에서 설명 (d) - 차원 공간의 벡터 및 행렬.
3. (d) - 차원 공간 : 특성을
3.1 배열
"배열" : 각 변수와 같은 변수를 수집는 고유의 이름과 같은 명령의 이름을 지정할 수있습니다.
정수로 이름을 사용할 수있습니다 변수를 배열합니다.
예를 들어, 배열을 포함 (d) 변수, 다음 정수 { 0, 1, 2, ..., (d-1) } 될 수있는 이름의 배열에서 변수에 할당됩니다.
3.2 (d) - 차원 벡터
"(d) - 차원 벡터" : (d) 변수의 배열합니다.
"벡터 구성 요소" : 변수를 벡터로합니다.
3.3 (d) - 차원 벡터 공간
"한 - 차원 공간" : 아래의 전체 집합을 하나씩 값을 변수를 저장할 수있습니다.
"(d) - 차원 공간" : 아래의 전체 집합을 조합의 값을 (d) 수있는 매개 변수의 배열에 의해 저장합니다.
공식 정의를 "벡터 공간" :
어디 (T)는 기본적인 유형 (예 : 실제 숫자, 정수, 복소수, 합리적 번호 등)를합니다.
어떤 변수라는 이름의 기본 유형은 "스칼라합니다."
a "(d) - 차원 벡터 공간은 (T) - 타입" (S)의 세트에서 두 개의 작업을 (d) - 차원 벡터, 벡터 이외 (+), 그리고 스칼라 곱셈 (*), 아래의 조건을 충족 :
(1) 벡터의 경우 임의의 두 (v) 및 (w)은 (S), 그럼 벡터 (v + w)도 (S);
(2) 만일 (u), (v), 그리고 3 개의 벡터 (w)에 대해서는 아무 (S), 그럼 (u + v) + w = u + (v + w);
[첨가제 교환]
(3) 만약 (w)은 임의의 두 벡터 (v) 및 (S), 그럼 (v + w) = (w + v);
[첨가제 결합]
(4)가 "제로 벡터," (0), (S), 같은 (v)에서 벡터를 찾으세요 (S), (v + (0)) = v;
[첨가제 신원]
(5) 만약 (c)는 어떠한 유형의 스칼라 (T), 그리고 어떤 (v)는 벡터 (S), 그럼이 제품 (c * v)는 벡터 (S);
(6) 만약 (a), (b), 그리고 스칼라 (c) 유형에 대해서는 아무 (T), 그리고 (w)에 대해서는 아무 (v) 및 벡터 (S), 그럼 (a + b) * v = a*v + b*v, 그리고 c*(v + w) = c*v + c*w;
[곱셈 분배]
(7) 유형의 경우 스칼라 (a) 및 (b)에 대해서는 아무 (T), 그리고 어떤 (v)는 벡터 (S), 그럼 (a*b)*v = a*(b*v);
(8) 만약 (T) 같은 유형의 "1" 스칼라 (1*1)=1가, 그리고 어떤 (v)는 벡터 (S), 그럼 (1*v) = v;
(9)의 각 (v)에 (S) 벡터의 벡터 (-1)*v = -v을 충족 v + (-v) = (0);
[첨가제 반전]
3.4 - 차원 벡터 코드를 (d)
아래의 코드 (d)하는 방법을 보여줍니다 - 차원 벡터,와 64 - 비트 부동 - 포인트 구성 요소를 구현할 수있습니다.
벡터를 나타내는 배열이 충분합니다.
아래의 코드에 포함된 배열은 클래스에 대해서만 편리합니다.
이 코드는 효율적인 의도가있는 것은 아닙니다.
구조 (예 : "struct", 값 유형)을 대표 고정 개수의 벡터 크기 (예 : 3 또는 4)은 훨씬 더 효율적인 것으로 보인다 - 차원 벡터 클래스보다 일반적인 (d) 여기에 게재합니다.
하지만 아래의 코드를 정의하는 벡터 플로팅 - 포인트 구성 요소,이 문서는 또한 벡터를 사용하는 구성 요소와 정수합니다.
아래의 코드를 쉽게 수정될 정수 벡터를 구현하는 구성 요소를합니다.
using System;
using System.Collections.Generic;
using System.Text;
// Multidimensional vector with 64-bit floating-point components:
public class VectorF64
{
private double[] components;
public int Dimensions()
{
if (null == this.components)
{
return (0);
}
return (this.components.Length);
}
public VectorF64()
{
this.components = null;
}
public VectorF64( params double[] paramValues )
{
this.components = null;
if (null == paramValues)
{
return;
}
int dimensions = paramValues.Length;
this.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
this.components[i] = paramValues[i];
}
}
public VectorF64( VectorF64 other )
{
this.components = null;
if (null == other)
{
return;
}
if (null == other.components)
{
return;
}
int dimensions = other.Dimensions();
this.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
this.components[i] = other.components[i];
}
}
public double this[int index]
{
get
{
if (null == this.components)
{
return (0.0);
}
if
(
(index >= 0)
&& (index < this.components.Length)
)
{
return (this.components[index]);
}
return (0.0);
}
set
{
if (null == this.components)
{
return;
}
if
(
(index >= 0)
&& (index < this.components.Length)
)
{
this.components[index] = value;
}
}
}
public void Write( int precision )
{
if (null == this.components)
{
Log.Write( String.Empty + '(' + ' ' + ')' );
return;
}
int dimensions = this.Dimensions();
if (0 == dimensions)
{
Log.Write( String.Empty + '(' + ' ' + ')' );
return;
}
// Determine the largest component width in characters
// so that we can make all components an equal width.
int largestComponentWidth = 1;
for (int i = 0; i < dimensions; i++)
{
// { index [,minwidth] [:typeCode[precision]] }
// (minwidth<0) means left-justify
String text = String.Format( String.Empty + '{' + '0' + ':'
+ 'g' + precision + '}', this[i] );
if (text.Length > largestComponentWidth)
{
largestComponentWidth = text.Length;
}
}
Log.Write( '(' );
for (int i = 0; i < dimensions; i++)
{
Log.Write( ' ' );
String text =
String.Format( String.Empty + '{' + '0' + ','
+ largestComponentWidth + ':' + 'g' + precision + '}',
this[i] );
Log.Write( text );
if ((i + 1) < dimensions)
{
Log.Write( ',' );
}
else
{
Log.Write( ' ' );
}
}
Log.Write( ')' );
}
public void WriteLine( int precision )
{
this.Write( precision );
Log.WriteLine();
}
public void WriteLine()
{
const int defaultPrecision = 8;
this.Write( defaultPrecision );
Log.WriteLine();
}
// . . .
public static void Test()
{
// A 3-dimensional vector with 64-bit floating-point components:
VectorF64 v3 = new VectorF64( 0.0, 1.0, 2.0 );
v3.WriteLine(); // ( 0, 1, 2 )
// A 4-dimensional vector with 64-bit floating-point components:
VectorF64 v4 = new VectorF64( 0.0, 1.0, 2.0, 3.0 );
v4.WriteLine(); // ( 0, 1, 2, 3 )
// . . .
}
}
"제로 (d) - 차원 벡터" : (d) 구성 요소를 모두 평등과 벡터를 0으로합니다.
public class VectorF64
{
// . . .
public static VectorF64 Zero( int dimensions )
{
VectorF64 zero = new VectorF64();
zero.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
zero[i] = 0.0;
}
return (zero);
}
// . . .
public static void Test()
{
// . . .
// An 8-dimensional vector with all 8 64-bit floating-point
// components set to zero:
VectorF64 z = VectorF64.Zero( 8 );
z.WriteLine(); // ( 0, 0, 0, 0, 0, 0, 0, 0 )
// . . .
}
}
3.5 (d) - 차원 공간 : 포인트
"(d) - 차원 공간 점" : (d) 변수의 배열이 특정 값 "(좌표 값)."
"(d) - 차원 공간을 생산지" : 모든 값을 변수를 배열을 (d) 평등을 0으로합니다.
3.6 (d) - 차원 벡터 : 없음 - 상대와 상대
a (d) - 차원 벡터가 "아닌 - 상대가" (d) - 차원 벡터를 직접 또는 구성의 상태를 나타냅니다.
a (d) - 차원 벡터가 (d) - 차원 벡터를 나타내는 "상대는" 일련의 구성 요소를 변경합니다.
벡터의 차이는 상대적인 두 개의 아닌 표현할 수있습니다 - 상대적인 벡터합니다.
주어진 상대적인 벡터, 결정이 아닌 벡터 - 상대적인 상태 또는 구성을 사용하는 상대적인 결합이 필요합니다 - 상대가 아닌 상대적인 벡터와 벡터합니다.
- 상대적인 벡터 및 상대 아닌 벡터는 모두 벡터합니다.
- 상대가 아닌 특정 벡터 여부를 지정해야합니다 때 또는 상대의 벡터가 정의합니다.
(d) - 차원 벡터가 아닌 것으로 해석 - 상대적인 다음 (d) - 차원 벡터 (d) - 차원 공간에 포인트를 표현할 수있습니다.
3.7 (d) - 차원 벡터 덧셈, 뺄셈, 그리고 스케일링
벡터 덧셈, 뺄셈, 그리고 스케일링 :
public class VectorF64
{
// . . .
public static VectorF64 operator +( VectorF64 a, VectorF64 b )
{
if ((null == a) || (null == b))
{
return (new VectorF64()); // Vector not specified.
}
if ((null == a.components) || (null == b.components))
{
return (new VectorF64()); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (new VectorF64()); // Vectors not the same size.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = a[i] + b[i];
}
return (result);
}
public static VectorF64 operator -( VectorF64 a, VectorF64 b )
{
if ((null == a) || (null == b))
{
return (new VectorF64()); // Vector not specified.
}
if ((null == a.components) || (null == b.components))
{
return (new VectorF64()); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (new VectorF64()); // Vectors not the same size.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = a[i] - b[i];
}
return (result);
}
public static VectorF64 operator -( VectorF64 a )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = (-( a[i] ));
}
return (result);
}
public static VectorF64 operator *( double scale, VectorF64 a )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = scale * a[i];
}
return (result);
}
public static VectorF64 operator *( VectorF64 a, double scale )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = scale * a[i];
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Examples of vector addition, subtraction, and scaling:
VectorF64 a = new VectorF64( 0.0, 1.0, 2.0, 3.0 );
a.WriteLine(); // ( 0, 1, 2, 3 )
VectorF64 b = new VectorF64( 3.0, 2.0, 1.0, 0.0 );
b.WriteLine(); // ( 3, 2, 1, 0 )
VectorF64 c = new VectorF64();
c.WriteLine(); // ( )
c = a + b;
c.WriteLine(); // ( 3, 3, 3, 3 )
c = a - b;
c.WriteLine(); // ( -3, -1, 1, 3 )
c = -b;
c.WriteLine(); // ( -3, -2, -1, 0 )
c = 3.0 * a;
c.WriteLine(); // ( 0, 3, 6, 9 )
// . . .
}
}
3.8 - 차원 벡터를 기준 (d)
공식 정의를 "기준으로" 벡터 공간 :
어디 (T)는 기본적인 유형 (예 : 실제 숫자, 정수, 복소수, 합리적 번호 등)를합니다.
어떤 변수라는 이름의 기본 유형은 "스칼라합니다."
(T) "-" (V)는 어디 "(d) - 차원 벡터 공간을 입력합니다."
(V)이 아닌 경우에는이 같은 { u1, u2, ..., ud } - 제로 벡터 (v)에서 모든 벡터 (V) "선형 조합을" 작성할 수있습니다 백터로서, v = c1*u1 + c2*u2 + ... + cd*ud, 어디 스칼라 { c1, c2, ..., cd }이 유형의 (T), 그럼으로 "스팬" (V)는 벡터 { u1, u2, ..., ud }합니다.
어떤 일련의 "스팬" 벡터 공간이 아닌 { u1, u2, ..., ud } - 제로 벡터 (V)은 (V)의 이름을 "기준으로합니다."
1 개의 간단한 "기반의" (d) - 차원 벡터 공간은 별개 (d) 집합을 (d) - 차원 벡터, 각각 한 구성 요소를 평등 및 다른 모든 구성 요소를 하나 평등을 0으로합니다.
그러한 기초 벡터는 "orthonormal," 즉, 그들은 상호 작용하는 - 수직 "(직교)" 및는 각 벡터는 단위 길이합니다.
각각의 이러한 벡터의 단위 좌표 벡터 (d) 축 중 하나를 평행하게합니다.
"선형 조합으로" 표현의 임의의 벡터 기반 벡터는 직접적으로, 각 구성 요소에 해당하는 임의의 벡터가 기준 곱한 벡터, 그리고 이들 제품은 함께 추가 임의 벡터를 형성합니다.
아래의 코드 벡터하는 방법을 보여줍니다 "선형 조합을" 기초로 표현될 수있습니다 벡터합니다.
아래에 임의의 코드 벡터를 정의하는 기준 세트를 orthonormal합니다.
public class VectorF64
{
// . . .
public static VectorF64 BasisVector( int dimensions, int componentIndex )
{
if (dimensions < 0)
{
// Invalid number of dimensions specified.
return (new VectorF64());
}
VectorF64 basisVector = VectorF64.Zero( dimensions );
if ((componentIndex >= 0) && (componentIndex < dimensions))
{
basisVector[ componentIndex ] = 1.0;
}
return (basisVector);
}
// . . .
public static void Test()
{
// . . .
// The 4 basis vectors of 4-dimensional space,
// each with 4 64-bit floating-point components:
VectorF64 b0 = VectorF64.BasisVector( 4, 0 );
b0.WriteLine(); // ( 1, 0, 0, 0 )
VectorF64 b1 = VectorF64.BasisVector( 4, 1 );
b1.WriteLine(); // ( 0, 1, 0, 0 )
VectorF64 b2 = VectorF64.BasisVector( 4, 2 );
b2.WriteLine(); // ( 0, 0, 1, 0 )
VectorF64 b3 = VectorF64.BasisVector( 4, 3 );
b3.WriteLine(); // ( 0, 0, 0, 1 )
// . . .
}
}
(d) - 차원 공간의 모든 벡터로 표현될 수있습니다 제품의 숫자와 단위 벡터의 합계 :
public class VectorF64
{
// . . .
public static void Test()
{
// . . .
// The following two vectors are equivalent:
// A 4-dimensional vector with 64-bit floating-point components:
VectorF64 va = new VectorF64( 0.1, 1.1, 2.2, 3.3 );
va.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )
// A 4-dimensional vector formed by scaling the 4 independent
// basis vectors for 4-dimensional space:
VectorF64 vb =
0.1 * VectorF64.BasisVector( 4, 0 )
+ 1.1 * VectorF64.BasisVector( 4, 1 )
+ 2.2 * VectorF64.BasisVector( 4, 2 )
+ 3.3 * VectorF64.BasisVector( 4, 3 );
vb.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )
// . . .
}
}
3.9 (d) - 차원 공간 : 거리를 점
어디가 (P) 차원 벡터를 나타내는 지점에서 (d) - (d) - 차원 공간을합니다.
어디가 (Q) 차원 벡터를 나타내는 지점에서 (d) - (d) - 차원 공간을합니다.
(d) - 차원 벡터가 어디 (R)를 나타내는 좌표를 얻을 수 (d) 변화를 가리 키 (P) 포인트 (Q); R = (Q - P)합니다.
한 - 차원 공간, P = ( p0 ), Q = ( q0 ), 그리고 R = (Q - P) = ( q0 - p0 )합니다.
이 두 지점 사이의 거리는 : Abs( q0 - p0 )합니다.
2 - 차원 공간, P = ( p0, p1 ), Q = ( q0, q1 ), 그리고 R = (Q - P) = ( q0-p0, q1-p1 )합니다.
해석에 수직으로 두 개의 수직 변위 - 삼각형을 오른쪽 측면에 해당하는 지점 사이의 거리를 사변의 삼각형의 길이를합니다.
the Pythagorean 수식 (a*a) + (b*b) = (c*c), 어디 (a)과 수직의 길이는 (b) 측면 - 삼각형을 오른쪽으로, 그리고 사변의 길이를 (c)은 (왜곡 쪽), 수 두 점 사이의 거리를 결정하는 데 사용 : Sqrt( Sq(q0-p0) + Sq(q1-p1) )합니다.
3 - 차원 공간, P = ( p0, p1, p2 ), Q = ( q0, q1, q2 ), 그리고 R = (Q - P) = ( q0-p0, q1-p1, q2-p2 )합니다.
수직 변위 측면으로 해석 ( q0-p0, q1-p1, 0 ) - 삼각형을 오른쪽으로, 그리고 Pythagorean을 사용하여 수식을 (P) 지점과 지점 사이의 거리를 ( q0, q1, p2 ) : d01 = Sqrt( Sq(q0-p0) + Sq(q1-p1) )합니다.
( q0-p0, q1-p1, 0 )는 수직 변위를 ( 0, 0, q2-p2 ) 진지 변환하고, 다른 권리 - 삼각형을 형성 수있습니다, 그리고 Pythagorean 수식을 다시 사용할 수있습니다.
이에 따라 거리를 가리 키 포인트 (Q)이 부여 (P) : Sqrt( Sq(d01) + Sq(q2-p2) ) = Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) ) = Sqrt( Sq(q0-p0) + Sq(q1-p1) + Sq(q2-p2) )합니다.
거리를 수식하는 방법을 확장하는 차원 공간을 2 - 3 - 차원 공간의 거리에 적용할 수있습니다 수식을 반복해서 결국 (d) 결정 - 차원 공간 : Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) + ... + Sq(qd-pd) )합니다.
아래의 코드 "길이의" 이름을 정의하는 기능을 (d) - 차원 벡터의 길이를 계산합니다.
벡터를 나타냅니다 때 두 지점 사이에서 진지 변환 (d) - 차원 공간, 벡터의 길이를 그 두 점 사이의 거리를 나타냅니다.
public class VectorF64
{
// . . .
public double Length()
{
if (null == this.components)
{
return (0.0); // Vector empty.
}
int dimensions = this.Dimensions();
double sumOfSquares = 0.0;
for (int i = 0; i < dimensions; i++)
{
sumOfSquares += (this[i] * this[i]);
}
double length = Math.Sqrt( sumOfSquares );
return (length);
}
public static double Length( VectorF64 a )
{
if (null == a)
{
return (0.0); // Vector not specified.
}
if (null == a.components)
{
return (0.0); // Vector is empty.
}
return (a.Length());
}
// . . .
public static void Test()
{
// . . .
// Example of vector length:
// A 6-dimensional vector representing a point (p):
VectorF64 p = new VectorF64( 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 );
p.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )
// A 6-dimensional vector representing a point (q):
VectorF64 q = new VectorF64( -5.0, 4.0, -3.0, 2.0, -1.0, 0.0 );
q.WriteLine(); // ( -5, 4, -3, 2, -1, 0 )
// A 6-dimensional vector representing the displacement
// from point (p) to point (q):
VectorF64 r = q - p;
r.WriteLine(); // ( -5, 3, -5, -1, -5, -5 )
// The distance between point (p) and point (q)
// in 6-dimensional space:
double distance = r.Length();
Log.WriteLine( distance ); // 10.4880884817015
// . . .
}
}
3.10 (d) - 차원 벡터 : 내적
"도트 상품을" (d) - 차원 벡터를 두 개의 숫자로 변환합니다.
아래의 코드를 계산합니다 벡터를 점으로의 산물이 :
public class VectorF64
{
// . . .
public static double Dot( VectorF64 a, VectorF64 b )
{
if ((null == a) || (null == b))
{
return (0.0); // Vector not specified.
}
if ((null == a.components) || (null == b.components))
{
return (0.0); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (0.0); // Vectors not the same size.
}
int dimensions = a.Dimensions();
double dotProduct = 0.0;
for (int i = 0; i < dimensions; i++)
{
dotProduct += (a[i] * b[i]);
}
return (dotProduct);
}
// . . .
}
의 모든 벡터, (A), Length(A) = Sqrt(Dot(A,A))합니다.
3.11 (d) - 차원 벡터 : 정의의 "병렬"
벡터 및 (B)가 "병렬로" (A)에 해당하는 경우 다음의 모든 :
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = A.Length()*B.Length()합니다.
아래의 코드를 결정 한 쌍의 경우 벡터가 병렬로 (아마 방지 - 정렬).
부동 - 소수점 수있습니다 부분 부분의 오류를 축적으로 인해 제한 정밀도, 그리고, 그러므로, 컴퓨터에 코드를 포함해야한다 - 영 공차 비교했을 때 아닌 부동 - 소수점합니다.
허용 오차 값의 코드를 포함 예,하지만 허용 오차 값이 예제 일부 작업에 적합되지 않을 수도있습니다.
public class VectorF64
{
// . . .
public static bool Parallel( VectorF64 a, VectorF64 b )
{
// Smallest normalized float : 1.1754943e-38
// Smallest normalized double: 2.2250738585072020e-308
double nonZeroThreshold = 1.0e-38; // conservative for double
// double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
double fractionalDifferenceThreshold = 1.0e-14; // conservative
if ((null == a) || (null == b))
{
return (false); // Vector is not specified.
}
if ((null == a.components) || (null == b.components))
{
return (false); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (false); // Vectors not the same size.
}
double lengthA = a.Length();
if (lengthA <= nonZeroThreshold)
{
return (false);
}
double lengthB = b.Length();
if (lengthB <= nonZeroThreshold)
{
return (false);
}
double oneImpliesParallel =
Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);
double absoluteDifferenceFromOne =
Math.Abs( oneImpliesParallel - 1.0 );
if (absoluteDifferenceFromOne <= fractionalDifferenceThreshold)
{
return (true);
}
return (false);
}
// . . .
public static void Test()
{
// . . .
// Example of testing for parallel vectors:
// A 6-dimensional vector:
VectorF64 vf = new VectorF64( 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 );
vf.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )
// A 6-dimensional vector:
VectorF64 vg = new VectorF64( 0.0, -2.0, -4.0, -6.0, -8.0, -10.0 );
vg.WriteLine(); // ( 0, -2, -4, -6, -8, -10 )
// Determine if the specified vectors are parallel
// (or "anti-aligned"):
bool parallel = VectorF64.Parallel( vf, vg );
Log.WriteLine( parallel ); // True
// Add a non-negligible displacement to a component of a vector:
vf[0] += 1.0e-5;
vf.WriteLine(); // ( 1E-05, 1, 2, 3, 4, 5 )
// Determine if the specified vectors are parallel
// (or "anti-aligned"):
parallel = VectorF64.Parallel( vf, vg );
Log.WriteLine( parallel ); // False
// . . .
}
}
3.12 (d) - 차원 벡터 : 정의를 "직각"
벡터의 모든 (A) 및 (B)은 다음과 같은 경우에 해당하는 "수직" :
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = 0합니다.
아래의 코드를 결정 한 쌍의 경우 벡터가 수직합니다. 부동 - 소수점 수있습니다 부분 부분의 오류를 축적으로 인해 제한 정밀도, 그리고, 그러므로, 컴퓨터에 코드를 포함해야한다 - 영 공차 비교했을 때 아닌 부동 - 소수점합니다.
허용 오차 값의 코드를 포함 예,하지만 허용 오차 값이 예제 일부 작업에 적합되지 않을 수도있습니다.
public class VectorF64
{
// . . .
public static bool Perpendicular( VectorF64 a, VectorF64 b )
{
// Smallest normalized float : 1.1754943e-38
// Smallest normalized double: 2.2250738585072020e-308
double nonZeroThreshold = 1.0e-38; // conservative for double
// double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
double fractionalDifferenceThreshold = 1.0e-14; // conservative
if ((null == a) || (null == b))
{
return (false); // Vector is not specified.
}
if ((null == a.components) || (null == b.components))
{
return (false); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (false); // Vectors not the same size.
}
double lengthA = a.Length();
if (lengthA <= nonZeroThreshold)
{
return (false);
}
double lengthB = b.Length();
if (lengthB <= nonZeroThreshold)
{
return (false);
}
double zeroImpliesPerpendicular =
Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);
double absoluteDifferenceFromZero =
Math.Abs( zeroImpliesPerpendicular );
if (absoluteDifferenceFromZero <= fractionalDifferenceThreshold)
{
return (true);
}
return (false);
}
// . . .
public static void Test()
{
// . . .
// Example of testing for perpendicular vectors:
// A 6-dimensional vector:
VectorF64 vf2 = new VectorF64( 0.0, 1.0, 2.0, 0.0, 4.0, 5.0 );
vf2.WriteLine(); // ( 0, 1, 2, 0, 4, 5 )
// A 6-dimensional vector:
VectorF64 vg2 = new VectorF64( 10.0, 0.0, 0.0, -5.0, 0.0, 0.0 );
vg2.WriteLine(); // ( 10, 0, 0, -5, 0, 0 )
// Determine if the specified vectors are perpendicular
bool perpendicular = VectorF64.Perpendicular( vf2, vg2 );
Log.WriteLine( perpendicular ); // True
// Add a non-negligible displacement to a component of a vector:
vf2[0] += 1.0e-13;
vf2.WriteLine(); // ( 1E-13, 1, 2, 0, 4, 5 )
// Determine if the specified vectors are perpendicular
perpendicular = VectorF64.Perpendicular( vf2, vg2 );
Log.WriteLine( perpendicular ); // False
// . . .
}
}
3.13 매트릭스
"매트릭스" : 컬렉션이 같은 변수의 고유한 조합을 각각의 변수가 "행" 이름과 "열" 이름을합니다.
"항목" : 변수를 모체로합니다.
정수로 사용될 수있습니다 "행" 이름과 "열" 이름의 변수를 모체합니다.
예를 들어, 매트릭스는 (totalRows) 행 및 (totalColumns) 열, 그 정수의 이름에 할당되는 { 0, 1, ..., (totalRows-1) } 수있습니다 행, 그리고 정수의 이름에 할당되는 { 0, 1, ..., (totalColumns-1) } 열 수있습니다.
따라서 변수를 지정하여 매트릭스를 지정할 수있습니다 한 쌍의 정수, ( row, column ), 행과 열의를 나타내는 지표의 조합에 해당하는 특정 변수합니다.
매트릭스가 "(totalRows) * (totalColumns)의" 크기를 지정 (또는 "(totalRows) 의해 (totalColumns))."
이 주문의 치수는 치수의 순서를 동일 항목을 지정하는 데 사용 매트릭스 "(( row, column ))."
[이 대회는 다소 유감스러운, 왜냐하면 많은 2 - 치수를 사용 (예 : 이미지, 그래프 등)를 일반적인 규칙은 다음과 좌표를 지정으로 "width * height" 치수로 "( horizontal, vertical )" (또는 "( x, y ))."
이것은 크기와 좌표의 순서를 반대로 행렬과 그 항목을 설명하는 데 사용합니다. ]
매트릭스 (totalColumns)의 이름은 "광장과" 같음 (totalRows); 그렇지 않으면, 매트릭스의 이름은 "직사각형합니다."
매트릭스 일련의 "행" 수있습니다 "벡터를" 포함하는 것으로 간주, 각 행에 변수를 어디에 속하는가를 벡터로 해석합니다.
매트릭스 수도있습니다 "벡터를 열" 세트를 포함하는 것으로 간주, 각 열의 변수를 어디에 속하는가를 벡터로 해석합니다.
매트릭스를 대표하는 다양한 종류의 수학의 관계를합니다.
매트릭스의 의미를, 그리고 적절한을 처리할 수있는 항목의 작업을 매트릭스의 문맥에 따라 달라집니다.
그러나 다음과 같은 기본적인 규칙을 모체와 관련된 산수가 많은 문맥, 그리고 이러한 기본적인 규칙은 다음 섹션에서 정의되어야합니다.
배열 및 매트릭스를 나타내는 (totalColumns) 값이 충분합니다.
(totalRows * totalColumns)의 배열은 변수 및 ( row, column )의 항목에 해당하는 수 인덱스의 배열 변수를 ((totalColumns * row) + column)합니다.
아래의 코드를 정의 행렬과 64 - 비트 부동 - 점 항목을합니다.
배열 및 매트릭스를 나타내는 (totalColumns) 값이 충분합니다.
아래의 코드는 (totalColumns) 값에 포함된 배열과 클래스,에만 사용이 편리합니다.
아래의 코드를 효율적인 의도가있는 것은 아닙니다.
구조 (예 : "struct", 값 유형)을 대표 매트릭스 특정 고정 치수 (예 : 2*2, 3*3, 또는 4*4)은 일반적인 것으로 보인다 (totalRows * totalColumns) 클래스보다 훨씬 더 효율적으로 여기에 게재합니다.
아래의 코드를 정의 비록 모체와 부동 - 점 항목,이 문서에서는 또한 정수 항목과 매트릭스를 사용합니다.
아래 코드를 쉽게 수정할 수있습니다 매트릭스와 정수 항목을 구현합니다.
using System;
using System.Collections.Generic;
using System.Text;
// Matrix with 64-bit floating-point entries:
public class MatrixF64
{
private int totalRows;
private int totalColumns;
private double[] entries;
// matrix[ row, column ] = entries[ (totalColumns * row) + column ]
public int Columns()
{
return (this.totalColumns);
}
public int Rows()
{
return (this.totalRows);
}
public MatrixF64()
{
this.totalRows = 0;
this.totalColumns = 0;
this.entries = null;
}
public MatrixF64( int rows, int columns, params double[] paramValues )
{
this.totalRows = 0;
this.totalColumns = 0;
this.entries = null;
if (rows <= 0)
{
return; // Specified an invalid row count.
}
if (columns <= 0)
{
return; // Specified an invalid column count.
}
int totalEntries = (rows * columns);
this.totalRows = rows;
this.totalColumns = columns;
this.entries = new double[totalEntries];
for (int k = 0; k < totalEntries; k++)
{
this.entries[k] = 0.0;
}
if (null == paramValues)
{
return; // No entries specified.
}
int totalParamValues = paramValues.Length;
if (totalParamValues != totalEntries)
{
// The number of specified entries does not match the
// total number of matrix entries.
return;
}
for (int k = 0; k < totalParamValues; k++)
{
this.entries[k] = paramValues[k];
}
}
public MatrixF64( MatrixF64 other )
{
this.totalRows = 0;
this.totalColumns = 0;
this.entries = null;
if (null == other)
{
return;
}
if
(
(null == other.entries)
|| (0 == other.totalRows)
|| (0 == other.totalColumns)
)
{
return;
}
int totalEntries = (other.totalRows * other.totalColumns);
if (other.entries.Length != totalEntries)
{
return;
}
this.totalRows = other.totalRows;
this.totalColumns = other.totalColumns;
this.entries = new double[totalEntries];
for (int k = 0; k < totalEntries; k++)
{
this.entries[k] = other.entries[k];
}
}
public double this[int row, int column]
{
get
{
if
(
(this.totalRows > 0)
&& (this.totalColumns > 0)
&& (null != this.entries)
&& (row >= 0)
&& (row < this.totalRows)
&& (column >= 0)
&& (column < this.totalColumns)
)
{
int k = (this.totalColumns * row) + column;
if ((k >= 0) && (k < this.entries.Length))
{
return (this.entries[k]);
}
}
return (0.0);
}
set
{
if
(
(this.totalRows > 0)
&& (this.totalColumns > 0)
&& (null != this.entries)
&& (row >= 0)
&& (row < this.totalRows)
&& (column >= 0)
&& (column < this.totalColumns)
)
{
int k = (this.totalColumns * row) + column;
if ((k >= 0) && (k < this.entries.Length))
{
this.entries[k] = value;
}
}
}
}
public void WriteLine( int precision )
{
if
(
(this.totalRows <= 0)
|| (this.totalColumns <= 0)
|| (null == this.entries)
)
{
Log.WriteLine( String.Empty + '[' + ' ' + ']' );
return;
}
// Determine the largest entry width in characters
// so that we can make all columns an equal width.
int largestEntryWidth = 1;
for (int i = 0; i < this.totalRows; i++)
{
for (int j = 0; j < this.totalColumns; j++)
{
// { index [,minwidth] [:typeCode[precision]] }
// (minwidth<0) means left-justify
String text = String.Format( String.Empty
+ '{' + '0' + ':' + 'g' + precision + '}', this[i,j] );
if (text.Length > largestEntryWidth)
{
largestEntryWidth = text.Length;
}
}
}
// Print each row of the matrix.
for (int i = 0; i < this.totalRows; i++)
{
Log.Write( '[' );
for (int j = 0; j < this.totalColumns; j++)
{
Log.Write( ' ' );
String text = String.Format( String.Empty
+ '{' + '0' + ',' + largestEntryWidth + ':' + 'g'
+ precision + '}', this[i,j] );
Log.Write( text );
if ((j + 1) < this.totalColumns)
{
Log.Write( ',' );
}
else
{
Log.Write( ' ' );
}
}
Log.WriteLine( ']' );
}
}
public void WriteLine()
{
const int defaultPrecision = 8;
this.WriteLine( defaultPrecision );
}
// . . .
public static void Test()
{
// A 5x3 matrix (5 rows x 3 columns) with
// 64-bit floating-point entries:
MatrixF64 m =
new MatrixF64
(
5, 3,
0.0, 1.0, 2.0, // row 0
3.0, 4.0, 5.0, // row 1
6.0, 7.0, 8.0, // row 2
9.0, 10.0, 11.0, // row 3
12.0, 13.0, 14.0 // row 4
);
m.WriteLine();
// [ 0, 1, 2 ] // row 0
// [ 3, 4, 5 ] // row 1
// [ 6, 7, 8 ] // row 2
// [ 9, 10, 11 ] // row 3
// [ 12, 13, 14 ] // row 4
// . . .
}
}
"제로 매트릭스" : 매트릭스와 같은 모든 항목을 0으로합니다.
public class MatrixF64
{
// . . .
public static MatrixF64 Zero( int rows, int columns )
{
MatrixF64 zero = new MatrixF64( rows, columns );
// The constructor above sets all entries to zero.
return (zero);
}
// . . .
public static void Test()
{
// . . .
// An 8x2 matrix (8 rows x 2 columns) with all 16
// 64-bit floating-point entries set to zero:
MatrixF64 z = MatrixF64.Zero( 8, 2 );
z.WriteLine();
// [ 0, 0 ] // row 0
// [ 0, 0 ] // row 1
// [ 0, 0 ] // row 2
// [ 0, 0 ] // row 3
// [ 0, 0 ] // row 4
// [ 0, 0 ] // row 5
// [ 0, 0 ] // row 6
// [ 0, 0 ] // row 7
// . . .
}
}
3.14 매트릭스 덧셈, 뺄셈, 곱셈
매트릭스 덧셈, 뺄셈, 곱셈합니다.
public class MatrixF64
{
// . . .
public static MatrixF64 operator +( MatrixF64 a, MatrixF64 b )
{
if ((null == a) || (null == b))
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );
if
(
(null == a.entries)
|| (null == b.entries)
|| (a.totalRows != b.totalRows)
|| (a.totalColumns != b.totalColumns)
)
{
return (result);
}
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < a.totalColumns; j++)
{
result[i, j] = a[i, j] + b[i, j];
}
}
return (result);
}
public static MatrixF64 operator -( MatrixF64 a, MatrixF64 b )
{
if ((null == a) || (null == b))
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );
if
(
(null == a.entries)
|| (null == b.entries)
|| (a.totalRows != b.totalRows)
|| (a.totalColumns != b.totalColumns)
)
{
return (result);
}
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < a.totalColumns; j++)
{
result[i, j] = a[i, j] - b[i, j];
}
}
return (result);
}
public static MatrixF64 operator -( MatrixF64 a )
{
if (null == a)
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );
if (null == a.entries)
{
return (result);
}
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < a.totalColumns; j++)
{
result[i, j] = (-( a[i, j] ));
}
}
return (result);
}
public static MatrixF64 operator *( double scale, MatrixF64 a )
{
if (null == a)
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );
if (null == a.entries)
{
return (result);
}
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < a.totalColumns; j++)
{
result[i, j] = scale * a[i, j];
}
}
return (result);
}
public static MatrixF64 operator *( MatrixF64 a, double scale )
{
if (null == a)
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );
if (null == a.entries)
{
return (result);
}
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < a.totalColumns; j++)
{
result[i, j] = scale * a[i, j];
}
}
return (result);
}
public static MatrixF64 operator *( MatrixF64 a, MatrixF64 b )
{
if ((null == a) || (null == b))
{
return (null);
}
MatrixF64 result = MatrixF64.Zero( a.totalRows, b.totalColumns );
// The number of columns of the first matrix must be equal
// to the number of rows of the second matrix.
if
(
(null == a.entries)
|| (null == b.entries)
|| (a.totalColumns != b.totalRows)
)
{
return (result);
}
// Entry (i,j) of the result is equal to the dot product
// of row (i) of (a) and column (j) of (b).
for (int i = 0; i < a.totalRows; i++)
{
for (int j = 0; j < b.totalColumns; j++)
{
double dotProduct = 0.0;
for (int k = 0; k < a.totalColumns; k++)
{
dotProduct += (a[i, k] * b[k, j]);
}
result[i, j] = dotProduct;
}
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Examples of matrix addition, subtraction, and multiplication:
MatrixF64 a =
new MatrixF64
(
3, 5,
0.0, 1.0, 2.0, 3.0, 4.0, // row 0
5.0, 6.0, 7.0, 8.0, 9.0, // row 1
10.0, 11.0, 12.0, 13.0, 14.0 // row 2
);
MatrixF64 b =
new MatrixF64
(
3, 5,
4.0, -3.0, 2.0, -1.0, 0.0, // row 0
-9.0, 8.0, -7.0, 6.0, -5.0, // row 1
14.0, -13.0, 12.0, -11.0, 10.0 // row 2
);
MatrixF64 c =
new MatrixF64
(
5, 3,
0.0, 1.0, 2.0, // row 0
3.0, 4.0, 5.0, // row 1
6.0, 7.0, 8.0, // row 2
9.0, 10.0, 11.0, // row 3
12.0, 13.0, 14.0 // row 4
);
MatrixF64 result = new MatrixF64();
result = a + b;
result.WriteLine();
// [ 4, -2, 4, 2, 4 ]
// [ -4, 14, 0, 14, 4 ]
// [ 24, -2, 24, 2, 24 ]
result = a - b;
result.WriteLine();
// [ -4, 4, 0, 4, 4 ]
// [ 14, -2, 14, 2, 14 ]
// [ -4, 24, 0, 24, 4 ]
result = -a;
result.WriteLine();
// [ 0, -1, -2, -3, -4 ]
// [ -5, -6, -7, -8, -9 ]
// [ -10, -11, -12, -13, -14 ]
result = 3.0 * a;
result.WriteLine();
// [ 0, 3, 6, 9, 12 ]
// [ 15, 18, 21, 24, 27 ]
// [ 30, 33, 36, 39, 42 ]
result = a * c; // (3x5) * (5x3) = (3x3)
result.WriteLine();
// [ 90, 100, 110 ]
// [ 240, 275, 310 ]
// [ 390, 450, 510 ]
result = c * a; // (5x3) * (3x5) = (5x5)
result.WriteLine();
// [ 25, 28, 31, 34, 37 ]
// [ 70, 82, 94, 106, 118 ]
// [ 115, 136, 157, 178, 199 ]
// [ 160, 190, 220, 250, 280 ]
// [ 205, 244, 283, 322, 361 ]
// . . .
}
}
"신원 매트릭스" : 스퀘어 매트릭스 (총 행 동등 총 열)과 항목이 같음을 (1) 대각선 (행 지수 평등을 열 항목을 색인), 그리고 다른 모든 항목과 같음 (0)합니다.
이 광장 매트릭스, (M)은 "자아" 곱한 "매트릭스," (I), 같은 수의 행 (및 열),이 제품이 같음 (M)합니다.
또한 제품을 생산하여 (M) 곱한 (I) 같음 (M)합니다.
따라서, "매트릭스가와" 유사한 번호를 "1의 정체성을" 곱셈의 숫자 (스칼라).
아래 코드를 모체로 정체성을 만듭니다 행 수를 지정합니다.
public class MatrixF64
{
// . . .
public static MatrixF64 Identity( int rows )
{
MatrixF64 identity = MatrixF64.Zero( rows, rows );
for (int i = 0; i < rows; i++)
{
identity[i, i] = 1.0;
}
return (identity);
}
// . . .
public static void Test()
{
// . . .
// Examples of multiplying by an identity matrix:
MatrixF64 identity3x3 = MatrixF64.Identity( 3 );
// [ 1, 0, 0 ]
// [ 0, 1, 0 ]
// [ 0, 0, 1 ]
MatrixF64 s3x3 =
new MatrixF64
(
3, 3,
0.0, 1.0, 2.0, // row 0
3.0, 4.0, 5.0, // row 1
6.0, 7.0, 8.0 // row 2
);
result = s3x3 * identity3x3;
result.WriteLine();
// [ 0, 1, 2 ]
// [ 3, 4, 5 ]
// [ 6, 7, 8 ]
// (the same as s3x3)
result = identity3x3 * s3x3;
result.WriteLine();
// [ 0, 1, 2 ]
// [ 3, 4, 5 ]
// [ 6, 7, 8 ]
// (the same as s3x3)
// . . .
}
}
3.15 매트릭스 : LU 감안; 위로 - 교체
"매트릭스 LU 감안" : 변환하는 절차는 스퀘어 매트릭스, (M), 두 개의 새 광장 매트릭스, (L) 및 (U) 애를와 같은 크기로 (M), 같은 (L) * (U) = (M), 그리고 같은 매트릭스 "(U)은" 고위 "삼각형" (대각선 아래에있는 모든 항목은 영), 그리고 매트릭스 "(L)이" 낮습니다 "삼각형" (모든 항목이 위에 대각선이 영)으로합니다.
모체의 일부로 사용할 수있습니다 LU 감안 프로 시저를 해결하는 시스템을보다 큰 방정식을, 아니면 반전의 모체를 찾으려면, 또는 모체를 찾으려면를 결정합니다.
매트릭스 LU 제거 절차를 감안 "Gauss-Jordan에 대한 대안입니다.
Gauss-Jordan 방정식을 제거 시스템을 필요로합니다 (A)*(x)=(b) 반면 매트릭스 LU 감안 (A)만을 필요로합니다.
또한, 이후의 양을 결정하는 LU 매트릭스 (A), 그것은 매우 간단합니다 (x) 주어진 어떠한 (b)를 결정합니다.
(x)의 벡터를 해결하기위한 절차를 (A)*(x)=(b) 주어진 (b) 및 LU 감안 (L)*(U)=(A), 포함되는 프로 시저의 이름 "위로 - 교체는" 여기에있습니다.
아래의 코드를 포함하고 절차에 대해 어떠한 요인을 계산 LU 광장, 아닌 - 단수 매트릭스합니다.
아래 코드를 포함하는 절차에 대해 LU 위로 - 교체합니다.
주의 사항 : 컴퓨터 L 및 U 요인에 아래 코드를 계산합니다 행 - permuted 버전을 지정 매트릭스합니다.
또한, L 및 U 매트릭스 검색 결과는 하나의 출력 매트릭스를 결합합니다.
public class MatrixF64
{
// . . .
public static void FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
(
MatrixF64 originalMatrix,
ref MatrixF64 LUFactorsMatrix,
ref int[] rowPermutationOfOriginalMatrix,
ref bool rowExchangeParityIsOdd
)
{
// ''LU factoring'' involves factoring a square matrix (M) in to a
// lower-triangular matrix (L), and an upper-triangular matrix (U),
// such that (L)*(U) = (M).
//
// However, the specified matrix (originalMatrix) might not be
// optimal for direct LU factoring, due to the locations of extreme
// values in the matrix. Therefore, this function instead implicitly
// factors a row-permuted version of originalMatrix, where the
// permutation of rows is determined by the values in the specified
// matrix. The specific row permutation selected by this function is
// returned in an array of row indices (rowPermutationOfOriginalMatrix).
// The resulting (L) and (U) factors are merged in to a single
// output matrix (LUFactorsMatrix). Therefore:
//
// (L part of LUFactorsMatrix) * (U part of LUFactorsMatrix)
// = (originalMatrix with rows permuted according to
// rowPermutationOfOriginalMatrix).
//
// Although factoring a row-permuted version of originalMatrix
// makes it more difficult to interpret the results of this function,
// the resulting LU factoring is likely to be more accurate. In a
// sense, this function indicates (via rowPermutationOfOriginalMatrix)
// how to permute the rows of originalMatrix to be able to produce
// the most accurate LU factoring directly, and this function produces
// that factoring (via the LUFactorsMatrix output).
//
// When using the (L) and (U) matrices (merged in to LUFactorsMatrix)
// to solve a system of equations, it is necessary to permute the rows
// of the solution vector of the system of equations according to
// rowPermutation.
//
// The output matrix (LUFactorsMatrix) is a combination of
// the (L) and (U) matrices:
//
// To form the (L) matrix from (LUFactorsMatrix):
// assume (0) for entries above the diagonal,
// assume (1) for entries on the diagonal,
// and use (LUFactorsMatrix) entries below the diagonal.
//
// To form the (U) matrix from (LUFactorsMatrix):
// assume (0) for entries below the diagonal,
// and use (LUFactorsMatrix) entries on and above the diagonal.
//
// The output array (rowPermutationOfOriginalMatrix) indicates how the
// rows of the original matrix have implicitly (not actually) been
// permuted.
//
// The output boolean (rowExchangeParityIsOdd) indicates if the parity
// of the permutation of rows is odd.
//
// This implementation is partly based on pseudo-code appearing in
// ''Introduction to Algorithms'' (Cormen; Lieserson; Rivest;
// 24th printing, 2000; MIT Press; ISBN 0-262-03141-8).
// See the section named ''Overview of LUP decomposition'', in
// chapter 31 (''Matrix Operations''). The implementation here follows
// the ''LUP-Decomposition'' pseudo-code appearing in a section named
// ''Computing an LUP decomposition''.
//
// This implementation also uses ideas found in the implementation of
// ''ludcmp'' in the book ''Numerical recipes in C : The art of
// scientific computing'' (Press; Teukolsky; Vetterling; Flannery;
// second edition; 1996 reprinting; Cambridge University Press).
// The overall loop structure here resembles that of ''ludcmp''.
// The idea of determining and caching row scale factors in advance of
// finding pivots is used here. The method in ''ludcmp'' to avoid zero
// pivot values has been modified here to handle excessively-small
// pivot values, too. HOWEVER, the row permutation indices produced by
// the following implementation is a true permutation of
// {0,1,...,(totalRows-1)}, whereas ''ludcmp'' (and ''lubksb'')
// interpret their ''permutation indices'' as swaps to perform
// (roughly, for each (i), swap b[ i ] and b[ indx[i] ]). So, the
// following implementation of LU-factoring is not directly compatible
// with ''ludcmp'' or ''lubksb''. Also, the following procedure
// does not destroy the original matrix (unlike ''ludcmp'').
double singularMatrixIfMaxRowElementIsLessThanThis = (1.0e-19);
double forcePivotsToHaveAtLeastThisAbsoluteValue = (1.0e-19);
LUFactorsMatrix = null;
rowPermutationOfOriginalMatrix = null;
rowExchangeParityIsOdd = false;
if (null == originalMatrix)
{
return; // No matrix specified.
}
if
(
(originalMatrix.totalRows <= 0)
|| (originalMatrix.totalColumns <= 0)
|| (null == originalMatrix.entries)
)
{
return; // Matrix is empty.
}
if (originalMatrix.totalRows != originalMatrix.totalColumns)
{
return; // Matrix is not square.
}
// Duplicate the original matrix
LUFactorsMatrix = new MatrixF64( originalMatrix );
// (Lines 2-3 of LUP-Decomposition)
// Initialize the row permutation array to the identity
// permutation.
rowPermutationOfOriginalMatrix = new int[LUFactorsMatrix.totalRows];
for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
{
rowPermutationOfOriginalMatrix[i] = i;
}
// For each row, determine the largest absolute value of
// the row elements, and use the reciprocal as the scale for
// that row.
VectorF64 rowScales = VectorF64.Zero( LUFactorsMatrix.totalRows );
for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
{
double largestElementAbsoluteValueInRow = 0.0;
for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
{
double absoluteElementValue =
Math.Abs( LUFactorsMatrix[i, j] );
if (absoluteElementValue >
largestElementAbsoluteValueInRow)
{
largestElementAbsoluteValueInRow =
absoluteElementValue;
}
}
if (largestElementAbsoluteValueInRow <
singularMatrixIfMaxRowElementIsLessThanThis)
{
return; // Matrix is singular
}
rowScales[i] = (1.0 / largestElementAbsoluteValueInRow);
}
// (Lines 4-18 of LUP-Decomposition)
// Go through the columns of the matrix.
for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
{
// (Lines 17-18 of LUP-Decomposition)
// (or equation (2.3.12) of NR)
for (int i = 0; i < j; i++)
{
double sum = LUFactorsMatrix[i, j];
for (int k = 0; k < i; k++)
{
sum -= (LUFactorsMatrix[i, k] * LUFactorsMatrix[k, j]);
}
LUFactorsMatrix[i, j] = sum;
}
// Go through all remaining rows and find the best pivot.
double largestScaledSum = 0.0;
int rowIndexOfLargestScaledSum = j;
for (int i = j; i < LUFactorsMatrix.totalRows; i++)
{
// (equation (2.3.13) of NR)
double sum = LUFactorsMatrix[i, j];
for (int k = 0; k < j; k++)
{
sum -= (LUFactorsMatrix[i, k] * LUFactorsMatrix[k, j]);
}
LUFactorsMatrix[i, j] = sum;
double scaledSum = rowScales[i] * Math.Abs( sum );
if (scaledSum >= largestScaledSum)
{
largestScaledSum = scaledSum;
rowIndexOfLargestScaledSum = i;
}
}
// If indeed we found a better pivot, then exchange rows.
if (j != rowIndexOfLargestScaledSum)
{
// (Line 12 of LUP-Decomposition)
// Exchange the row permutation indices
int tempRowIndex = rowPermutationOfOriginalMatrix[j];
rowPermutationOfOriginalMatrix[j] =
rowPermutationOfOriginalMatrix[rowIndexOfLargestScaledSum];
rowPermutationOfOriginalMatrix[rowIndexOfLargestScaledSum] =
tempRowIndex;
// (Lines 13-14 of LUP-Decomposition)
// Exchange the elements of the rows
for (int k = 0; k < LUFactorsMatrix.totalColumns; k++)
{
double temp = LUFactorsMatrix[rowIndexOfLargestScaledSum, k];
LUFactorsMatrix[rowIndexOfLargestScaledSum, k] =
LUFactorsMatrix[j, k];
LUFactorsMatrix[j, k] = temp;
}
// Exchange the row scale factors
double scaleFactor =
rowScales[rowIndexOfLargestScaledSum];
rowScales[rowIndexOfLargestScaledSum] = rowScales[j];
rowScales[j] = scaleFactor;
// Invert the overall row exchange parity
rowExchangeParityIsOdd = (!(rowExchangeParityIsOdd));
}
// Force the pivot element to have at least a certain
// absolute value.
if (Math.Abs( LUFactorsMatrix[j, j] ) <
forcePivotsToHaveAtLeastThisAbsoluteValue)
{
if (LUFactorsMatrix[j, j] < 0.0)
{
LUFactorsMatrix[j, j] =
(-(forcePivotsToHaveAtLeastThisAbsoluteValue));
}
else
{
LUFactorsMatrix[j, j] =
forcePivotsToHaveAtLeastThisAbsoluteValue;
}
}
// If not the final column, then divide all column elements
// below the diagonal by the pivot element, matrixLU[j,j].
// (Lines 15-16 of LUP-Decomposition)
if (j != (LUFactorsMatrix.totalColumns - 1))
{
double reciprocalOfPivot = (1.0 / LUFactorsMatrix[j, j]);
for (int i = (j + 1); i < LUFactorsMatrix.totalRows; i++)
{
LUFactorsMatrix[i, j] *= reciprocalOfPivot;
}
}
}
}
public static void LUBacksubstitution
(
MatrixF64 LUFactorsMatrix,
int[] rowPermutationOfOriginalMatrix,
VectorF64 givenProductVector,
ref VectorF64 solutionVector
)
{
// This implementation is based on pseudo-code appearing in
// ''Introduction to Algorithms'' (Cormen; Lieserson; Rivest;
// 24th printing, 2000; MIT Press; ISBN 0-262-03141-8).
// See the section named ''Overview of LUP decomposition'', in
// chapter 31 (''Matrix Operations''). The implementation here
// follows the ''LUP-Solve'' pseudo-code appearing in a
// section named ''forward and back substitution''.
solutionVector = null;
if (null == LUFactorsMatrix)
{
return; // No matrix specified.
}
if (null == rowPermutationOfOriginalMatrix)
{
return; // No permutation specified.
}
if (null == givenProductVector)
{
return; // No product vector specified.
}
if
(
(null == LUFactorsMatrix.entries)
|| (LUFactorsMatrix.totalRows <= 0)
|| (LUFactorsMatrix.totalColumns <= 0)
)
{
return; // Matrix is empty.
}
if (LUFactorsMatrix.totalRows !=
LUFactorsMatrix.totalColumns)
{
return; // Matrix is not square.
}
if (givenProductVector.Dimensions() !=
LUFactorsMatrix.totalRows)
{
return; // Product vector size not equal to matrix row count.
}
// Copy the product vector in to the result.
solutionVector = new VectorF64( givenProductVector );
// (See LUP-Solve, lines 2-3)
for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
{
double sum =
givenProductVector[rowPermutationOfOriginalMatrix[i]];
for (int j = 0; j < i; j++)
{
sum -= (LUFactorsMatrix[i, j] * solutionVector[j]);
}
solutionVector[i] = sum;
}
// (See LUP-Solve, lines 4-5)
for (int i = (LUFactorsMatrix.totalRows - 1); i >= 0; i--)
{
double sum = solutionVector[i];
for
(
int j = (i + 1);
j < LUFactorsMatrix.totalColumns;
j++
)
{
sum -= (LUFactorsMatrix[i, j] * solutionVector[j]);
}
double diagonalElement = LUFactorsMatrix[i, i];
if (diagonalElement != 0.0)
{
solutionVector[i] = (sum / diagonalElement);
}
}
}
// . . .
public static void Test()
{
// . . .
// Example of LU factoring and back-substitution:
MatrixF64 a3x3 =
new MatrixF64
(
3, 3,
0.0, 1.0, 2.0, // row 0
3.0, 4.0, 5.0, // row 1
6.0, 7.0, 8.0 // row 2
);
int[] rowPermutationOfOriginalMatrix = null;
bool rowInterchangeParityIsOdd = false;
MatrixF64 a3x3LU = null;
MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
(
a3x3,
ref a3x3LU,
ref rowPermutationOfOriginalMatrix,
ref rowInterchangeParityIsOdd
);
a3x3LU.WriteLine();
// [ 6, 7, 8 ]
// [ 0, 1, 2 ]
// [ 0.5, 0.5, 1e-19 ]
// The matrix above is a combination of the L and U
// matrices. The L matrix is 0 above the diagonal,
// 1 on the diagonal, and the shown values below the
// diagonal. The U matrix is 0 below the diagonal,
// and the shown values on and above the diagonal.
// This LU factoring is of a ROW-PERMUTED version
// of the original matrix.
// The following L and U matrices are manually formed
// by inspecting the LU factoring matrix above.
MatrixF64 L3x3 =
new MatrixF64
(
3, 3,
1.0, 0.0, 0.0, // row 0
0.0, 1.0, 0.0, // row 1
0.5, 0.5, 1.0 // row 2
);
MatrixF64 U3x3 =
new MatrixF64
(
3, 3,
6.0, 7.0, 8.0, // row 0
0.0, 1.0, 2.0, // row 1
0.0, 0.0, 0.0 // row 2
);
// The product (L)*(U) produces a ROW-PERMUTED version
// of the original matrix:
result = L3x3 * U3x3;
result.WriteLine( 4 );
// [ 6, 7, 8 ]
// [ 0, 1, 2 ]
// [ 3, 4, 5 ]
VectorF64 b3x1 = new VectorF64( 1.0, 2.0, 3.0 );
VectorF64 x3x1 = null;
MatrixF64.LUBacksubstitution
(
a3x3LU,
rowPermutationOfOriginalMatrix,
b3x1,
ref x3x1
);
// Solution vector
x3x1.WriteLine();
// ( -0.66666667, 1, 0 )
// Both the given b3x1 and this x3x1 are relative to the
// original matrix, a3x3. The a3x3LU for a ROW-PERMUTED
// version of a3x3, but LUBacksubstitution accepts a
// non-permuted product vector (e.g., b3x1) and produces
// a non-permuted solution vector (e.g., x3x1).
// Check solution by multiplying the original matrix a3x3
// by the solution vector x3x1, to get a product vector.
VectorF64 checkb3x1 = a3x3 * x3x1;
checkb3x1.WriteLine();
// ( 1, 2, 3 )
// This matches the b3x1 vector we specified above, so
// the solution is valid.
// . . .
}
}
3.16 매트릭스 : 결정
"결정" : 어떤 광장 (n * n) 모체로 변환하는 함수가 (A) 숫자를 det(A), 같은 :
(1) 행렬 (B) 결과를 교환하는 경우에는 두 개의 행, 또는 두 개의 기둥, (A)의 모체를 det(B) = (-(det(A)));
(2) 어떤 경우에는 곱한 결과를 모체 (B) 행, 또는 열, (A)의 모체를 몇 (c), 그럼 det(B) = c * det(A);
(3) 여러 개 추가하는 경우에는 하나의 결과를 모체 (B) 행을 다른 행, 열 중 하나 또는 여러 개의 다른 컬럼을 추가, 그럼 det(B) = det(A)합니다.
(4) 만약 (A)는 상단 - 삼각형 매트릭스 (A[i,j]=0의 모든 (i>j)) 또는 더 낮은 - 삼각형 매트릭스 (A[i,j]=0의 모든 (i<j)), 다음 det(A) = (A[0,0] * A[1,1] * ... * A[n-1,n-1]);
(예를 들어, 매트릭스는 하나 정체성을 결정; det(I) = 1합니다.)
규칙을 (1), (2), 그리고 (3), 사용할 수있습니다에서 제거하는 프로세스의 이름 "Gaussian, 어떠한 광장 매트릭스를 삼각형으로 변환 매트릭스합니다.
규칙을 사용할 수있습니다 (4) 삼각형을 계산한다 매트릭스를 결정합니다.
정의를 공식 "결정" :
매트릭스의 모든 (n * n) 어디 M[n](K) 이상의 하위 집합을 표시 필드 (K)합니다.
the "결정은" 2 F:M[n](K) --> K의 고유한 기능을 (F) 같은 특성 :
(1) F은 다중 교체에 관해서는 열 (또는 행); 그리고,
(2) F( I ) = 1합니다.
(D)의 "다중" 기능을 (A) a (n * n) 모체로 작성할 수있습니다 : D(A) = Sum( A[0,k[0]] * A[1,k[1]] * ... * A[n-1,k[n-1]] * D( e[k[0]], e[k[1]], ..., e[k[n-1]] ) ), 어디 (n^n)의 합계는 전체 조합의 점거 0 <= k[i] <= (n-1), 그리고 매트릭스의 정체성을 어디에 (j) 행 e[j]를 나타냅니다.
이러한 특징으로하는 함수의 값을 D( e[k[0]], e[k[1]], ..., e[k[n-1]] ) 수있습니다.
"다중" 함수가 "번갈아" 다중 기능, (D), 같은 D( ..., e[i], ..., e[i], ... ) = 0, 그리고 D( ..., e[i], e[j], ... ) = (-( D( ..., e[j], e[i], ... ) ))합니다.
따라서, 스와핑 열 (또는 행) 기호의 기능을 변경합니다.
또한, D( e[k[0]], ..., e[k[n-1]] )가 0이라는 용어의 조합 k[i] 값을 경우에는 관여하지 않습니다의 모든 고유 값을; 경우에는 순열 집합의 숫자 값은 {0,1,...,(n-1)}합니다.
보내는 D( I ) = 1 (D( e[0], e[1], ..., e[n-1] ) = 1), 교체 다중 특성을 결합하여 위에서 설명한 경우를 의미하는 모든 다중 기능을 번갈아 D( e[k[0]], e[k[1]], ..., e[k[n-1]] )의 값을 결정할 수있습니다.
- 제로의 기능이 아닌 k[i] 값 세트가있는 경우에만 순열의 {0,1,...,(n-1)}, 그리고 진도 중 하나가 아닌 경우 - 영, 그리고 서명이 필요로 변환하는 스왑의 개수를 순열 신원 순열합니다.
매트릭스의 (n * n)의 값을 결정 (A) 수있습니다 제품의 양식을 계산 (sgn(p) * A[0,p[0]] * A[1,p[1]] * ... * A[(n-1),p[n-1]])을 추가하여 각 순열 (p)의 숫자에 대한 {0,1,2,...,(n-1)}합니다.
(sgn(p)) 나타낸다이라는 용어의 "서명" (또는 스왑 카운트)의 순열 (p), 어디 (sgn(p)) 같음 (p)은 "짝수면" (+1) "순열과" 같음 (p)가 "홀수면 순열" (-1)합니다.
(n!) permutations의 숫자 {0,1,2,...,(n-1)}가 있기 때문에,이 수식에있는 (n!) summands합니다.
다른 절차를 계산 결정 (예 : 그 사건 Gaussian 철폐, 또는 LU 감안, 또는 확장을 미성년자 등)를 암시적으로 계산 수량 중간 계층을 계산한다 수 있도록 해주는 이러한 절차를 (n^3) 단계의 순서를 결정합니다.
매트릭스가 0의 경우에는 결정의 모체가 반대하지 않습니다.
매트릭스가 아닌 경우에는이 결정 - 0, 매트릭스는 반대합니다.
매트릭스 계수를 대표하는 경우에는 시스템을 선형 방정식, 그리고 결정의 모체가 0, 다음의 방정식가없는 경우 고유의 시스템 솔루션을합니다.
매트릭스 계수를 대표하는 경우에는 시스템을 선형 방정식, 그리고 결정의 모체가 아닌 - 0, 그 시스템을 방정식는 고유의 솔루션을합니다.
아래의 코드를 포함 어떠한 결정을위한 절차 광장 매트릭스 계산합니다.
결정에 대한 1*1, 2*2, 3*3, 그리고 4*4 행렬은 명시적인 수식을 계산합니다.
명시적인 수식을 사용하여 작은 행렬을 계산하는 요인을 계산 결과는 일반적인 프로 시저를 사용하여보다 빠르게 그 결정 요인을 계산합니다.
일반 케이스를 사용하는 절차에 LU 감안,하지만 컴퓨터에 해당하는 이미 많은 다른 방법을 결정합니다.
public class MatrixF64
{
// . . .
private double Determinant1x1()
{
if
(
(this.totalRows != 1)
|| (this.totalColumns != 1)
|| (null == this.entries)
)
{
return (0.0);
}
// The determinant of a 1x1 matrix is simply
// the value of the single element.
return ( this[0,0] );
}
private double Determinant2x2()
{
if
(
(this.totalRows != 2)
|| (this.totalColumns != 2)
|| (null == this.entries)
)
{
return (0.0);
}
return
(
+ this[0,0] * this[1,1]
- this[0,1] * this[1,0]
);
}
private double Determinant3x3()
{
if
(
(this.totalRows != 3)
|| (this.totalColumns != 3)
|| (null == this.entries)
)
{
return (0.0);
}
return
(
+ this[0,0] * this[1,1] * this[2,2]
+ this[0,1] * this[1,2] * this[2,0]
+ this[0,2] * this[1,0] * this[2,1]
- this[0,0] * this[1,2] * this[2,1]
- this[0,1] * this[1,0] * this[2,2]
- this[0,2] * this[1,1] * this[2,0]
);
}
private double Determinant4x4()
{
if
(
(this.totalRows != 4)
|| (this.totalColumns != 4)
|| (null == this.entries)
)
{
return (0.0);
}
return
(
+ this[0, 0] * this[1, 1] * this[2, 2] * this[3, 3]
+ this[0, 0] * this[1, 2] * this[2, 3] * this[3, 1]
+ this[0, 0] * this[1, 3] * this[2, 1] * this[3, 2]
+ this[0, 1] * this[1, 0] * this[2, 3] * this[3, 2]
+ this[0, 1] * this[1, 2] * this[2, 0] * this[3, 3]
+ this[0, 1] * this[1, 3] * this[2, 2] * this[3, 0]
+ this[0, 2] * this[1, 0] * this[2, 1] * this[3, 3]
+ this[0, 2] * this[1, 1] * this[2, 3] * this[3, 0]
+ this[0, 2] * this[1, 3] * this[2, 0] * this[3, 1]
+ this[0, 3] * this[1, 0] * this[2, 2] * this[3, 1]
+ this[0, 3] * this[1, 1] * this[2, 0] * this[3, 2]
+ this[0, 3] * this[1, 2] * this[2, 1] * this[3, 0]
- this[0, 0] * this[1, 1] * this[2, 3] * this[3, 2]
- this[0, 0] * this[1, 2] * this[2, 1] * this[3, 3]
- this[0, 0] * this[1, 3] * this[2, 2] * this[3, 1]
- this[0, 1] * this[1, 0] * this[2, 2] * this[3, 3]
- this[0, 1] * this[1, 2] * this[2, 3] * this[3, 0]
- this[0, 1] * this[1, 3] * this[2, 0] * this[3, 2]
- this[0, 2] * this[1, 0] * this[2, 3] * this[3, 1]
- this[0, 2] * this[1, 1] * this[2, 0] * this[3, 3]
- this[0, 2] * this[1, 3] * this[2, 1] * this[3, 0]
- this[0, 3] * this[1, 0] * this[2, 1] * this[3, 2]
- this[0, 3] * this[1, 1] * this[2, 2] * this[3, 0]
- this[0, 3] * this[1, 2] * this[2, 0] * this[3, 1]
);
}
public double Determinant()
{
if
(
(this.totalRows <= 0)
|| (this.totalColumns <= 0)
|| (null == this.entries)
)
{
return (0.0); // Matrix is empty.
}
if (this.totalRows != this.totalColumns)
{
// Matrix is not square
return (0.0);
}
// Simple cases
if (1 == this.totalRows) { return (this.Determinant1x1()); }
if (2 == this.totalRows) { return (this.Determinant2x2()); }
if (3 == this.totalRows) { return (this.Determinant3x3()); }
if (4 == this.totalRows) { return (this.Determinant4x4()); }
int[] rowPermutationOfOriginalMatrix = null;
bool rowExchangeParityIsOdd = false;
MatrixF64 originalMatrix = new MatrixF64( this );
MatrixF64 LUFactorsMatrix = null;
MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
(
originalMatrix,
ref LUFactorsMatrix,
ref rowPermutationOfOriginalMatrix,
ref rowExchangeParityIsOdd
);
if ((null == LUFactorsMatrix)
|| (null == rowPermutationOfOriginalMatrix))
{
return (0.0);
}
double determinant = 1.0;
if (true == rowExchangeParityIsOdd)
{
determinant = (-1.0);
}
for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
{
determinant *= LUFactorsMatrix[j, j];
}
return (determinant);
}
// . . .
public static void Test()
{
// . . .
// Examples of matrix determinants:
MatrixF64 d2x2 =
new MatrixF64
(
2, 2,
2.0, 5.0, // row 0
-4.0, -7.0 // row 1
);
double detd2x2 = d2x2.Determinant();
Log.WriteLine( detd2x2 );
// detd2x2 = 6
MatrixF64 d3x3 =
new MatrixF64
(
3, 3,
2.0, 5.0, 7.0, // row 0
-4.0, -1.0, 6.0, // row 1
9.0, 8.0, 3.0 // row 2
);
double detd3x3 = d3x3.Determinant();
Log.WriteLine( detd3x3 );
// detd3x3 = 67
MatrixF64 d4x4 =
new MatrixF64
(
4, 4,
7.0, -5.0, 2.0, 4.0, // row 0
3.0, 2.0, 6.0, 3.0, // row 1
-9.0, 8.0, -3.0, 2.0, // row 2
5.0, 3.0, 2.0, 5.0 // row 3
);
double detd4x4 = d4x4.Determinant();
Log.WriteLine( detd4x4 );
// detd4x4 = 1457
// . . .
}
}
3.17 (d) - 차원 벡터 : 교차 상품
"크로스 제품" :하는 함수와 관련된 (d) - 차원 공간을 (d-1) 목록을 순서로 변환 (d) - 차원 벡터, { A(0), A(1), ..., A(d-2) }로 (d) - 차원 벡터, 그러한하는 기능이 아래에있는 속성 :
(1) 만약 A(i)=0 (0 벡터),를 찾으세요 0 <= i <= (d-2), 그럼 Cross( A(0), A(1), ..., A(d-2) )=0 (0 벡터라고 함).
벡터의 목록을 교차 상품의 지시가 0이 목록에있는 경우 벡터가 0;
(2) 벡터 쌍있는 경우, A(i) 및 A(j)은 어떠한 0 <= i <= (d-2) 및 0 <= j <= (d-2)과 (i!=j)은 병렬 (Abs(Dot(A(i),A(j))) = Length(A(i)) * Length(A(j))), 그럼 Cross( A(0), A(1), ..., A(d-2) )=0 (0 벡터라고 함).
벡터의 목록을 교차 상품의 지시가 0이 목록에있는 경우가 병렬로 두 개의 벡터;
(3) 모든 벡터 A(i)가 아닌 경우 - 0, 그리고 만약 A(i)가 병렬로 A(j)의 모든 0 <= i <= (d-2) 및 0 <= j <= (d-2)과 (i!=j) 다음의 모든 B = Cross( A(0), A(1), ..., A(d-2) )가 Dot(A(i),B)=0 같은 0 <= i <= (d-2)합니다.
교차 상품의 목록을 주문한 경우에는 벡터가 아닌 - 0, 그 결과는 직각 교차 상품의 목록에있는 모든 벡터의 지시 벡터;
(4) 만약 (c) 숫자 값은 다음 Cross( (c * A(0)), A(1), ..., A(d-2) ) = Cross( A(0), (c * A(1)), ..., A(d-2) ) = ... = Cross( A(0), A(1), ..., (c * A(d-2)) ) = c * Cross( A(0), A(1), ..., A(d-2) )합니다.
순서 목록에 주어진 벡터를 크로스와 벡터의 제품 주문 목록을 곱한 벡터 중 하나를 특정 숫자 값은 이에 상응하는 명령 목록을 곱한 벡터의 제품을 교차하는 숫자 값;
(5) 주어진 두 숫자 (i) 및 (j), 어디 0 <= i <= (d-2) 및 (i!=j) 및 0 <= j <= (d-2), 그리고 순서 목록을 (d-1) (d) - 차원 벡터, { A(0), A(1), ..., A(d-2) }하고, 다른 명령 목록을 (d-1) (d) - 차원 벡터, { B(0), B(1), ..., B(d-2) }, 모든 ((k != i) && (k != j))과 같은 B(k) = A(k) 0 <= k <= (d-2), 그리고 같은 B(i) = A(j) 및 B(j) = A(i), 그럼 Cross( A(0), A(1), ..., A(d-2) ) = (-1) * Cross( B(0), B(1), ..., B(d-2) )합니다.
교차 상품의 목록을 주문한 경우에는 벡터가 아닌 - 0, 그 반대의 흔적은 상호 교차 제품은 동일한 명령 목록을 벡터의 제품을 제외하고 교환이 정확하게 두 개의 벡터 (스왑).
주어진 기준 벡터 e(k), 0 <= k <= (d-1), (d) - 차원 공간의 교차 상품의 주문 목록을 계산하여 결정 (d-1) 벡터의 계산은 아래에 모체 (d*d) :
e(0), e(1), ..., e(d-1),
A( 0 )[0], A( 0 )[1], ..., A( 0 )[d-1],
A( 1 )[0], A( 1 )[1], ..., A( 1 )[d-1],
...,
A(d-2)[0], A(d-2)[1], ..., A(d-2)[d-1]
the 결정의 모체가되지 않아 번호, 그러나이 대안은 벡터, 어디에 해당 수치는 계수 벡터를 기준으로 (d)합니다.
2 - 차원 공간 및 벡터 A = ( ax, ay ) :
Cross( A )
= Determinant
(
e(x), e(y),
ax, ay
)
= ay * e(x)
- ax * e(y)
= ( ay, -ax )
그 결과 벡터는 수직으로 단일 입력 벡터합니다.
x-y 비행기가 같은 경우에는 본 x 증가 향상을 상향 y 오른쪽 방향 및 방향, 다음은 25 - 턴 "시계 방향으로" 교차 상품 결과는 상대적으로 벡터의 입력합니다.
크로스 제품에 두 개의 - 차원 공간의 예입니다 :
Cross( e(x) ) = (-1) * e(y)
Cross( e(y) ) = e(x)
3 - 차원 공간을, 그리고 벡터 A = ( ax, ay, az ) 및 B = ( bx, by, bz ) :
Cross( A, B )
= Determinant
(
e(x), e(y), e(z),
ax, ay, az,
bx, by, bz
)
= (ay*bz - az*by) * e(x)
+ (az*bx - ax*bz) * e(y)
+ (ax*by - ay*bx) * e(z)
= ( (ay*bz - az*by), (az*bx - ax*bz), (ax*by - ay*bx) )
3 - 차원의 예입니다 크로스 제품에 공간 :
Cross( e(x), e(y) ) = e(z)
Cross( e(y), e(x) ) = (-1) * e(z)
Cross( e(y), e(z) ) = e(x)
Cross( e(z), e(y) ) = (-1) * e(x)
Cross( e(z), e(x) ) = e(y)
Cross( e(x), e(z) ) = (-1) * e(y)
4 - 차원 공간을, 그리고 벡터 A = ( ax, ay, az, aw ), B = ( bx, by, bz, bw ), 그리고 C = ( cx, cy, cz, cw ) :
Cross( A, B, C )
= Determinant
(
e(x), e(y), e(z), e(w),
ax, ay, az, aw,
bx, by, bz, bw,
cx, cy, cz, cw
)
= ( ay*bz*cw - ay*bw*cz + az*bw*cy - az*by*cw + aw*by*cz - aw*bz*cy) * e(x)
+ (-ax*bz*cw + ax*bw*cz - az*bw*cx + az*bx*cw - aw*bx*cz + aw*bz*cx) * e(y)
+ ( ax*by*cw - ax*bw*cy + ay*bw*cx - ay*bx*cw + aw*bx*cy - aw*by*cx) * e(z)
+ (-ax*by*cz + ax*bz*cy - ay*bz*cx + ay*bx*cz - az*bx*cy + az*by*cx) * e(w)
= ( ( ay*bz*cw - ay*bw*cz + az*bw*cy - az*by*cw + aw*by*cz - aw*bz*cy),
(-ax*bz*cw + ax*bw*cz - az*bw*cx + az*bx*cw - aw*bx*cz + aw*bz*cx),
( ax*by*cw - ax*bw*cy + ay*bw*cx - ay*bx*cw + aw*bx*cy - aw*by*cx),
(-ax*by*cz + ax*bz*cy - ay*bz*cx + ay*bx*cz - az*bx*cy + az*by*cx) )
4 - 차원의 예입니다 크로스 제품에 공간 :
Cross( e(x), e(y), e(z) ) = (-1) * e(w)
Cross( e(x), e(z), e(y) ) = e(w)
Cross( e(y), e(x), e(z) ) = e(w)
Cross( e(y), e(z), e(x) ) = (-1) * e(w)
Cross( e(z), e(x), e(y) ) = (-1) * e(w)
Cross( e(z), e(y), e(x) ) = e(w)
Cross( e(x), e(y), e(w) ) = e(z)
Cross( e(x), e(w), e(y) ) = (-1) * e(z)
Cross( e(y), e(x), e(w) ) = (-1) * e(z)
Cross( e(y), e(w), e(x) ) = e(z)
Cross( e(w), e(x), e(y) ) = e(z)
Cross( e(w), e(y), e(x) ) = (-1) * e(z)
Cross( e(x), e(z), e(w) ) = (-1) * e(y)
Cross( e(x), e(w), e(z) ) = e(y)
Cross( e(z), e(x), e(w) ) = e(y)
Cross( e(z), e(w), e(x) ) = (-1) * e(y)
Cross( e(w), e(x), e(z) ) = (-1) * e(y)
Cross( e(w), e(z), e(x) ) = e(y)
Cross( e(y), e(z), e(w) ) = e(x)
Cross( e(y), e(w), e(z) ) = (-1) * e(x)
Cross( e(z), e(y), e(w) ) = (-1) * e(x)
Cross( e(z), e(w), e(y) ) = e(x)
Cross( e(w), e(y), e(z) ) = e(x)
Cross( e(w), e(z), e(y) ) = (-1) * e(x)
아래의 코드를 계산합니다 - 상품을 2 개 이상의 벡터의 교차합니다.
이 테스트 사례보기 - 제로 결과 벡터가 수직이 아닌 모든 벡터의 입력합니다.
public class MatrixF64
{
// . . .
public static VectorF64 Cross( params VectorF64[] parameterArray )
{
if (null == parameterArray)
{
return(new VectorF64());
}
int totalVectors = parameterArray.Length;
// The number of dimensions of the space must be one larger
// than the number of specified vectors.
int dimensions = (1 + totalVectors);
if (dimensions < 2)
{
// The cross product does not exist for space with
// fewer than two dimensions.
return (new VectorF64());
}
// All specified vectors must exist and must have a number
// of components equal to the number of dimensions of the space.
for (int k = 0; k < totalVectors; k++)
{
if (null == parameterArray[k])
{
// Vector missing.
return (new VectorF64());
}
else if (null == parameterArray[k].components)
{
// Vector is empty.
return (new VectorF64());
}
else if (parameterArray[k].components.Length != dimensions)
{
// Vector has the wrong number of components.
return (new VectorF64());
}
}
// Form a (d*d) matrix with the (d-1) supplied vectors
// forming the final (d-1) rows of the matrix.
MatrixF64 matrix = MatrixF64.Zero( dimensions, dimensions );
for (int i = 1; i < dimensions; i++)
{
VectorF64 rowVector = parameterArray[ i - 1 ];
for (int j = 0; j < dimensions; j++)
{
matrix[i, j] = rowVector[j];
}
}
VectorF64 result = VectorF64.Zero( dimensions );
// For each component of the result vector, set the first
// row of the matrix to a basis vector, compute the matrix
// determinant, and use the resulting value as the
// component of the result vector. This is inefficient,
// due to the determinant being computed (d) times.
// Clearly it would be better to have explicit formulas
// for 2-dimensional, 3-dimensional, and 4-dimensional
// cross-products.
for (int i = 0; i < dimensions; i++)
{
// Set the first row of the matrix to be the basis
// vector for the coordinate axis with index (i).
for (int j = 0; j < dimensions; j++)
{
matrix[0, j] = 0.0;
}
matrix[0, i] = 1.0;
// Compute the determinant of the modified matrix.
double determinant = matrix.Determinant();
// Set component (i) of the result to the determinant
// that was computed.
result[i] = determinant;
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Examples of cross products:
// Three-dimensional example:
VectorF64 vcp1x3a = new VectorF64( 1.0, 2.0, 3.0 );
VectorF64 vcp1x3b = new VectorF64( 3.0, 1.0, 2.0 );
VectorF64 vcp1x3 = VectorF64.Cross( vcp1x3a, vcp1x3b );
vcp1x3.WriteLine(); // ( 1, 7, -5 )
// Verify that the result is perpendicular to the original
// vectors:
Log.WriteLine( VectorF64.Perpendicular( vcp1x3, vcp1x3a ) );
Log.WriteLine( VectorF64.Perpendicular( vcp1x3, vcp1x3b ) );
// True, True
// Four-dimensional example:
VectorF64 vcp1x4a = new VectorF64( 1.0, 2.0, 3.0, 4.0 );
VectorF64 vcp1x4b = new VectorF64( 4.0, 1.0, 2.0, 3.0 );
VectorF64 vcp1x4c = new VectorF64( 3.0, 4.0, 1.0, 2.0 );
VectorF64 vcp1x4 = VectorF64.Cross( vcp1x4a, vcp1x4b, vcp1x4c );
vcp1x4.WriteLine(); // ( 4, 4, 44, -36 )
// Verify that the result is perpendicular to the original
// vectors:
Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4a ) );
Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4b ) );
Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4c ) );
// True, True, True
// . . .
}
}
3.18 매트릭스 : 반전
"매트릭스 반전" : 매트릭스의 광장 매트릭스 관련하여 동일한 크기와 같은 또 다른 광장의 두 행렬이 제품은 "매트릭스의 정체성합니다."
매트릭스가 연결된 경우에는 반전 매트릭스, 매트릭스 길은 오직 한 그러한 반대합니다.
결정의 경우에는 모체가 0, 그럼 매트릭스의 이름은 "단수," 그리고 관련 반전이없는 매트릭스 매트릭스합니다.
아래의 코드를 계산합니다 반전의 광장, 아닌 - 단수 매트릭스합니다.
반전에 대한 1*1, 2*2, 3*3, 그리고 4*4 행렬은 명시적인 수식을 계산합니다.
명시적인 수식을 사용하는 일반적인 절차를 사용하여보다 빠르게 수도있습니다.
또한 안정적인 수식을 명시합니다.
일반 케이스를 사용하는 절차에 LU 감안,하지만 반전에 해당하는 이미 많은 다른 방법의 컴퓨팅 매트릭스합니다.
public class MatrixF64
{
// . . .
private MatrixF64 Inverse1x1()
{
if
(
(this.totalRows != 1)
|| (this.totalColumns != 1)
|| (null == this.entries)
)
{
return (MatrixF64.Zero( 1, 1 )); // Matrix is empty.
}
if (0.0 == this[0,0])
{
return ( MatrixF64.Zero( 1, 1 ) ); // Matrix has no inverse.
}
MatrixF64 inverse = MatrixF64.Zero( 1, 1 );
// The inverse of a 1x1 matrix is simply the
// reciprocal of the single entry.
inverse[0,0] = (1.0 / this[0,0]);
return (inverse);
}
private MatrixF64 Inverse2x2()
{
if
(
(this.totalRows != 2)
|| (this.totalColumns != 2)
|| (null == this.entries)
)
{
return (MatrixF64.Zero( 2, 2 )); // Matrix is empty.
}
double determinant = this.Determinant2x2();
if (0.0 == determinant)
{
return (MatrixF64.Zero( 2, 2 )); // Matrix has no inverse.
}
MatrixF64 inverse = MatrixF64.Zero( 2, 2 );
inverse[0,0] = this[1,1];
inverse[0,1] = (-(this[0,1]));
inverse[1,0] = (-(this[1,0]));
inverse[1,1] = this[0,0];
double factor = (1.0 / determinant);
for ( int i = 0; i < inverse.totalRows; i++ )
{
for ( int j = 0; j < inverse.totalColumns; j++ )
{
inverse[i,j] *= factor;
}
}
return (inverse);
}
private MatrixF64 Inverse3x3()
{
if
(
(this.totalRows != 3)
|| (this.totalColumns != 3)
|| (null == this.entries)
)
{
return (MatrixF64.Zero( 3, 3 )); // Matrix is empty.
}
double determinant = this.Determinant3x3();
if (0.0 == determinant)
{
return (MatrixF64.Zero( 3, 3 )); // Matrix has no inverse.
}
MatrixF64 inverse = MatrixF64.Zero( 3, 3 );
inverse[0, 0] =
this[1, 1] * this[2, 2]
- this[1, 2] * this[2, 1];
inverse[0, 1] =
this[0, 2] * this[2, 1]
- this[0, 1] * this[2, 2];
inverse[0, 2] =
this[0, 1] * this[1, 2]
- this[0, 2] * this[1, 1];
inverse[1, 0] =
this[1, 2] * this[2, 0]
- this[1, 0] * this[2, 2];
inverse[1, 1] =
this[0, 0] * this[2, 2]
- this[0, 2] * this[2, 0];
inverse[1, 2] =
this[0, 2] * this[1, 0]
- this[0, 0] * this[1, 2];
inverse[2, 0] =
this[1, 0] * this[2, 1]
- this[1, 1] * this[2, 0];
inverse[2, 1] =
this[0, 1] * this[2, 0]
- this[0, 0] * this[2, 1];
inverse[2, 2] =
this[0, 0] * this[1, 1]
- this[0, 1] * this[1, 0];
double factor = (1.0 / determinant);
for (int i = 0; i < inverse.totalRows; i++)
{
for (int j = 0; j < inverse.totalColumns; j++)
{
inverse[i, j] *= factor;
}
}
return (inverse);
}
private MatrixF64 Inverse4x4()
{
if
(
(this.totalRows != 4)
|| (this.totalColumns != 4)
|| (null == this.entries)
)
{
return (MatrixF64.Zero( 4, 4 )); // Matrix is empty.
}
double determinant = this.Determinant4x4();
if (0.0 == determinant)
{
return (MatrixF64.Zero( 4, 4 )); // Matrix has no inverse.
}
MatrixF64 inverse = MatrixF64.Zero( 4, 4 );
inverse[0,0] =
+ this[1,1] * this[2,2] * this[3,3]
+ this[1,2] * this[2,3] * this[3,1]
+ this[1,3] * this[2,1] * this[3,2]
- this[1,1] * this[2,3] * this[3,2]
- this[1,2] * this[2,1] * this[3,3]
- this[1,3] * this[2,2] * this[3,1];
inverse[0,1] =
+ this[0,1] * this[2,3] * this[3,2]
+ this[0,2] * this[2,1] * this[3,3]
+ this[0,3] * this[2,2] * this[3,1]
- this[0,1] * this[2,2] * this[3,3]
- this[0,2] * this[2,3] * this[3,1]
- this[0,3] * this[2,1] * this[3,2];
inverse[0,2] =
+ this[0,1] * this[1,2] * this[3,3]
+ this[0,2] * this[1,3] * this[3,1]
+ this[0,3] * this[1,1] * this[3,2]
- this[0,1] * this[1,3] * this[3,2]
- this[0,2] * this[1,1] * this[3,3]
- this[0,3] * this[1,2] * this[3,1];
inverse[0,3] =
+ this[0,1] * this[1,3] * this[2,2]
+ this[0,2] * this[1,1] * this[2,3]
+ this[0,3] * this[1,2] * this[2,1]
- this[0,1] * this[1,2] * this[2,3]
- this[0,2] * this[1,3] * this[2,1]
- this[0,3] * this[1,1] * this[2,2];
inverse[1,0] =
+ this[1,0] * this[2,3] * this[3,2]
+ this[1,2] * this[2,0] * this[3,3]
+ this[1,3] * this[2,2] * this[3,0]
- this[1,0] * this[2,2] * this[3,3]
- this[1,2] * this[2,3] * this[3,0]
- this[1,3] * this[2,0] * this[3,2];
inverse[1,1] =
+ this[0,0] * this[2,2] * this[3,3]
+ this[0,2] * this[2,3] * this[3,0]
+ this[0,3] * this[2,0] * this[3,2]
- this[0,0] * this[2,3] * this[3,2]
- this[0,2] * this[2,0] * this[3,3]
- this[0,3] * this[2,2] * this[3,0];
inverse[1,2] =
+ this[0,0] * this[1,3] * this[3,2]
+ this[0,2] * this[1,0] * this[3,3]
+ this[0,3] * this[1,2] * this[3,0]
- this[0,0] * this[1,2] * this[3,3]
- this[0,2] * this[1,3] * this[3,0]
- this[0,3] * this[1,0] * this[3,2];
inverse[1,3] =
+ this[0,0] * this[1,2] * this[2,3]
+ this[0,2] * this[1,3] * this[2,0]
+ this[0,3] * this[1,0] * this[2,2]
- this[0,0] * this[1,3] * this[2,2]
- this[0,2] * this[1,0] * this[2,3]
- this[0,3] * this[1,2] * this[2,0];
inverse[2,0] =
+ this[1,0] * this[2,1] * this[3,3]
+ this[1,1] * this[2,3] * this[3,0]
+ this[1,3] * this[2,0] * this[3,1]
- this[1,0] * this[2,3] * this[3,1]
- this[1,1] * this[2,0] * this[3,3]
- this[1,3] * this[2,1] * this[3,0];
inverse[2,1] =
+ this[0,0] * this[2,3] * this[3,1]
+ this[0,1] * this[2,0] * this[3,3]
+ this[0,3] * this[2,1] * this[3,0]
- this[0,0] * this[2,1] * this[3,3]
- this[0,1] * this[2,3] * this[3,0]
- this[0,3] * this[2,0] * this[3,1];
inverse[2,2] =
+ this[0,0] * this[1,1] * this[3,3]
+ this[0,1] * this[1,3] * this[3,0]
+ this[0,3] * this[1,0] * this[3,1]
- this[0,0] * this[1,3] * this[3,1]
- this[0,1] * this[1,0] * this[3,3]
- this[0,3] * this[1,1] * this[3,0];
inverse[2,3] =
+ this[0,0] * this[1,3] * this[2,1]
+ this[0,1] * this[1,0] * this[2,3]
+ this[0,3] * this[1,1] * this[2,0]
- this[0,0] * this[1,1] * this[2,3]
- this[0,1] * this[1,3] * this[2,0]
- this[0,3] * this[1,0] * this[2,1];
inverse[3,0] =
+ this[1,0] * this[2,2] * this[3,1]
+ this[1,1] * this[2,0] * this[3,2]
+ this[1,2] * this[2,1] * this[3,0]
- this[1,0] * this[2,1] * this[3,2]
- this[1,1] * this[2,2] * this[3,0]
- this[1,2] * this[2,0] * this[3,1];
inverse[3,1] =
+ this[0,0] * this[2,1] * this[3,2]
+ this[0,1] * this[2,2] * this[3,0]
+ this[0,2] * this[2,0] * this[3,1]
- this[0,0] * this[2,2] * this[3,1]
- this[0,1] * this[2,0] * this[3,2]
- this[0,2] * this[2,1] * this[3,0];
inverse[3,2] =
+ this[0,0] * this[1,2] * this[3,1]
+ this[0,1] * this[1,0] * this[3,2]
+ this[0,2] * this[1,1] * this[3,0]
- this[0,0] * this[1,1] * this[3,2]
- this[0,1] * this[1,2] * this[3,0]
- this[0,2] * this[1,0] * this[3,1];
inverse[3,3] =
+ this[0,0] * this[1,1] * this[2,2]
+ this[0,1] * this[1,2] * this[2,0]
+ this[0,2] * this[1,0] * this[2,1]
- this[0,0] * this[1,2] * this[2,1]
- this[0,1] * this[1,0] * this[2,2]
- this[0,2] * this[1,1] * this[2,0];
double factor = (1.0 / determinant);
for (int i = 0; i < inverse.totalRows; i++)
{
for (int j = 0; j < inverse.totalColumns; j++)
{
inverse[i, j] *= factor;
}
}
return (inverse);
}
public MatrixF64 Inverse()
{
if
(
(this.totalRows <= 0)
|| (this.totalColumns <= 0)
|| (null == this.entries)
)
{
return (MatrixF64.Zero( 1, 1 )); // Matrix is empty.
}
if (this.totalRows != this.totalColumns)
{
// Matrix is not square
return (MatrixF64.Zero( 1, 1 ));
}
// Simple cases
if (1 == this.totalRows) { return (this.Inverse1x1()); }
if (2 == this.totalRows) { return (this.Inverse2x2()); }
if (3 == this.totalRows) { return (this.Inverse3x3()); }
if (4 == this.totalRows) { return (this.Inverse4x4()); }
int[] rowPermutationOfOriginalMatrix = null;
bool rowExchangeParityIsOdd = false;
MatrixF64 originalMatrix = new MatrixF64( this );
MatrixF64 LUFactorsMatrix = null;
MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
(
originalMatrix,
ref LUFactorsMatrix,
ref rowPermutationOfOriginalMatrix,
ref rowExchangeParityIsOdd
);
if ((null == LUFactorsMatrix)
|| (null == rowPermutationOfOriginalMatrix))
{
return (MatrixF64.Zero( this.totalRows, this.totalColumns ));
}
VectorF64 columnVector = VectorF64.Zero( totalRows );
VectorF64 solutionVector = VectorF64.Zero( totalRows );
MatrixF64 inverse =
MatrixF64.Zero( this.totalRows, this.totalColumns );
for (int j = 0; j < inverse.totalColumns; j++)
{
for (int i = 0; i < inverse.totalRows; i++)
{
columnVector[i] = 0.0;
}
columnVector[j] = 1.0;
MatrixF64.LUBacksubstitution
(
LUFactorsMatrix,
rowPermutationOfOriginalMatrix,
columnVector,
ref solutionVector
);
if (null != solutionVector)
{
for (int i = 0; i < inverse.totalRows; i++)
{
inverse[i, j] = solutionVector[i];
}
}
}
return (inverse);
}
// . . .
public static void Test()
{
// . . .
// Examples of matrix inverses:
MatrixF64 m2x2 =
new MatrixF64
(
2, 2,
2.0, 5.0, // row 0
-4.0, -7.0 // row 1
);
MatrixF64 inversem2x2 = m2x2.Inverse();
inversem2x2.WriteLine();
// [ -1.1666667, -0.83333333 ]
// [ 0.66666667, 0.33333333 ]
MatrixF64 prodinvm2x2andm2x2 = inversem2x2 * m2x2;
prodinvm2x2andm2x2.WriteLine();
// [ 1, 8.8817842e-16 ]
// [ 0, 1 ]
// This product is very close to a
// 2x2 identity matrix, as it should be.
MatrixF64 prodm2x2andinvm2x2 = m2x2 * inversem2x2;
prodm2x2andinvm2x2.WriteLine();
// [ 1, 0 ]
// [ 0, 1 ]
// This product is the 2x2 identity matrix,
// as it should be.
MatrixF64 m3x3 =
new MatrixF64
(
3, 3,
2.0, 5.0, 7.0, // row 0
-4.0, -1.0, 6.0, // row 1
9.0, 8.0, 3.0 // row 2
);
MatrixF64 inversem3x3 = m3x3.Inverse();
inversem3x3.WriteLine();
// [ -0.76119403, 0.6119403, 0.55223881 ]
// [ 0.98507463, -0.85074627, -0.59701493 ]
// [ -0.34328358, 0.43283582, 0.26865672 ]
MatrixF64 prodinvm3x3andm3x3 = inversem3x3 * m3x3;
prodinvm3x3andm3x3.WriteLine();
// [ 1, 0, 4.4408921e-16 ]
// [ 0, 1, 0 ]
// [ 0, 0, 1 ]
// This product is very close to a 3x3 identity matrix,
// as it should be.
MatrixF64 prodm3x3andinvm3x3 = m3x3 * inversem3x3;
prodm3x3andinvm3x3.WriteLine();
// [ 1, -4.4408921e-16, 4.4408921e-16 ]
// [ 0, 1, -2.220446e-16 ]
// [ -4.4408921e-16, 0, 1 ]
// This product is very close to a 3x3 identity matrix,
// as it should be.
// . . .
}
}
3.19 모체와 벡터 곱셈의 산물
매트릭스 (M) the 곱셈의 산물 (a)는 벡터 및 벡터 (b); (M)*(a) = (b)합니다.
(M) 모체로 "변환" (a) 벡터 벡터 (b)합니다.
아래 코드를 계산합니다 모체와 벡터 곱셈의 산물합니다.
public class MatrixF64
{
// . . .
public static VectorF64 operator *( MatrixF64 m, VectorF64 v )
{
if (null == m)
{
return (null); // Matrix is not specified.
}
if
(
(null == m.entries)
|| (m.totalRows <= 0)
|| (m.totalColumns <= 0)
)
{
return (null); // Matrix is empty.
}
if (null == v)
{
// Vector is not specified.
return (VectorF64.Zero( m.totalRows ));
}
if (v.Dimensions() != m.totalColumns)
{
// The number of columns of the matrix must be equal
// to the number of rows of the vector.
return (VectorF64.Zero( m.totalRows ));
}
// The result vector has the same number of rows as the matrix.
VectorF64 result = VectorF64.Zero( m.totalRows );
// Component (i) of the result vector is equal to the
// dot product of row (i) of the matrix with the vector.
for (int i = 0; i < m.totalRows; i++)
{
double dotProduct = 0.0;
for (int j = 0; j < m.totalColumns; j++)
{
dotProduct += (m[i, j] * v[j]);
}
result[i] = dotProduct;
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Examples of a product of a matrix and a vector:
MatrixF64 t3x3 =
new MatrixF64
(
3, 3,
2.0, 5.0, 7.0, // row 0
-4.0, -1.0, 6.0, // row 1
9.0, 8.0, 3.0 // row 2
);
VectorF64 p3x1 = new VectorF64( 1.0, 2.0, 3.0 );
VectorF64 q3x1 = t3x3 * p3x1;
q3x1.WriteLine();
// ( 33, 12, 34 )
// The multiplicative product of the inverse
// of the matrix and the result vector computed
// above should reproduce the original vector.
MatrixF64 inverset3x3 = t3x3.Inverse();
VectorF64 prodinvt3x3andq3x1 = inverset3x3 * q3x1;
prodinvt3x3andq3x1.WriteLine();
// ( 1, 2, 3 )
// This vector is equal to the original vector,
// as expected.
// . . .
}
}
3.20 동종 동질 매트릭스를 사용하여 벡터로 번역
"번역" : T(s) 수술로 지정된 특정 벡터 (s), 그것에 대응하는 벡터로 변환 (r) 모든 벡터 (r + s); T(s) * (r) = (r + s)합니다.
반전의 T(-s)은 T(s); Inverse(T(s)) = T(-s); T(-s) * (r) = (r - s)합니다.
번역 작업을 표현할 수 매트릭스, 매트릭스의 번역을 곱한 같은 벡터는 그 벡터의 효과를 번역합니다.
the 공헌의 번역 작업의 결과 벡터의 구성 요소에 따라 다릅니다하지, 직접적이든 간접적이든, 원래의 구성 요소를 벡터합니다.
따라서, 모체로의 번역이되어야합니다 활성화에 기여하는 방식으로 구조로의 번역 결과에 영향을하지 않고, 직접적으로 또는 간접적으로하여 원래의 구성 요소를 벡터합니다.
벡터 a "균질 벡터가" 같음을 최종 구성 요소를 1합니다.
a "균질 모체가" 연속으로 행렬을 최종 0 모든 항목을 제외하고는 최종 엔트리에 동등한 1합니다.
the 곱셈 제품은 모체와 다른 동종 동질 행렬이 균질 매트릭스합니다.
the 곱셈 제품의 균질 모체와 벡터가 동종 동질 벡터합니다.
재미있는 특성을 하나의 항목으로이 제품은 동종의 마지막 열 매트릭스의 마지막 항목을 제외하고는 그 결과의 구성 요소들 직접적으로 벡터, 영향을받는하지 않고, 직접적이든 간접적이든, 그리고 상황의 구성 요소 의 원래 벡터합니다.
따라서, 균질로의 번역 작업을 표현할 수 매트릭스, 매트릭스 등 균질로 번역 벡터를 사용할 수있습니다.
만약 우리의 위치와 방향을 나타내는 소원을 (d) - 차원 공간, 그리고 우리를 번역 매트릭스를 사용하기 원하는 위치에서, 다음과 동종 동질 행렬 벡터를 사용할 수있습니다.
그러나이 균질 (d+1) 있어야합니다 구성 요소를 벡터, 그리고 균질 매트릭스 ((d+1)*(d+1)) 항목이 있어야합니다.
동종의 최종 구성 요소의 벡터 및 행렬의 마지막 행의 균질하지 (d) 중 하나에 해당하는 좌표를 대변하기 위해 우리의 소원 (d) - 차원 공간, 그 대신 봉사를에게만 행렬을 할 수있게 작업을 (d)에서 독립적으로 좌표 값을합니다.
균질 행렬과 벡터를 사용하여 균질 변형 및 적용을보다 쉽게 변환 기능을 복합 벡터지만 다른 작업을 더욱 불편합니다.
(d) - 차원 공간의 위치 또는 방향을 대표 균질 벡터를 사용하여 벡터가 (d+1) 구성 요소를 의미합니다과 같음의 최종 구성 요소를 1합니다.
컴퓨터를 사용하는 벡터를 균질 도트의 산물이 정기적으로 dot - 제품 기능을 통합 구성 요소를 암시적으로 (d) 도트 상품의 첫번째로 인해 마지막으로 적합하지 않다 1의 구성 요소의 값을 1합니다.
따라서, 제품의 도트를 (d) 요소의 관련성이 높은 균질 벡터 ((d+1) 구성 요소), 벡터해야 할 점은 제품의 균질 "벡터 내적" 기능을 사용하는 특수 "균질의" 최종 구성 요소를 간단하게 벡터를 건너 뜁니다.
또한 도트 상품을 수도로 계산된 정기적인 내적 기능을 1에 대한 이해가 일정한 액수의 결과에서 감액해야과 관련된 결과를 해석하기 전에 (d) 관련성이 높은 좌표를합니다.
아래의 코드 매트릭스 수있습니다 형성하는 방법을 보여줍니다 사용될 수있는 다음 벡터로 번역합니다.
public class MatrixF64
{
// . . .
public static MatrixF64 FormHomogeneousTranslationMatrix( VectorF64 v )
{
// This method assumes the specified vector is a homogeneous
// vector, where the final component is not relevant to the
// translation. Thus, we form a square homogeneous matrix
// with a total number of rows equal to the number of
// components of the specified vector. We form an identity
// matrix of the required size, and copy all but the final
// component of the specified vector to the final column of
// the matrix.
if (null == v)
{
return (MatrixF64.Zero( 1, 1 )); // Vector is not specified.
}
if (v.Dimensions() <= 0)
{
return (MatrixF64.Zero( 1, 1 )); // Vector is empty.
}
MatrixF64 result =
MatrixF64.Identity( v.Dimensions() );
// Add all but the final component of the specified vector
// to the final column of the result matrix. The final
// entry of the final column of the matrix will remain one (1).
for (int i = 0; i < (result.totalRows - 1); i++)
{
result[i, (result.totalColumns - 1)] = v[i];
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Example of using a homogeneous matrix to
// translate a homogeneous vector:
// Forming a homogeneous matrix that represents
// a translation:
VectorF64 homogeneousTranslationVector4x1 =
new VectorF64( 10.0, 20.0, 30.0, 1.0 );
MatrixF64 translation4x4 =
MatrixF64.FormHomogeneousTranslationMatrix
( homogeneousTranslationVector4x1 );
translation4x4.WriteLine();
// [ 1, 0, 0, 10 ]
// [ 0, 1, 0, 20 ]
// [ 0, 0, 1, 30 ]
// [ 0, 0, 0, 1 ]
// Using the homogeneous matrix to translate
// a homogeneous vector:
VectorF64 homogeneousVector =
new VectorF64( 5.0, 6.0, 7.0, 1.0 );
VectorF64 translatedVector =
translation4x4 * homogeneousVector;
translatedVector.WriteLine();
// ( 15, 26, 37, 1 )
// The relevant vector components (5,6,7)
// were translated by (10,20,30) by the
// homogeneous translation matrix.
// . . .
}
}
3.21 (d) - 차원 공간 : 로테이션
"회전 (d) - 차원 공간" : (R) 지정하는 작업 (S), 2 - 차원 회전 비행기, 회전 각도 (t), 그리고 회전 중심점 (c), 그것에 대응하는 포인트로 변환 (p) 아무 지점이나 (q), 같은 :
(1) Length( q - c ) = Length( p - c )하며 새로운 목표 지점 사이의 거리와 같은 회전 중심점 사이의 거리는 기존 지점과 회전 중심점합니다.
따라서, 새 지점이 (d) - 차원의 표면에있는 특정 영역;
(2) 어디 (P) 평행하게 회전하는 비행기는 비행기를 (p) 포인트 (S)을 포함합니다.
비행기가 될 수있을 (q) 포인트 (P)합니다.
따라서, 새 포인트는 차원에서 특정 비행기를 두 개의 - (d) - 차원 공간;
(3) Dot( (q - c), (p - c) ) = Length( q - c ) * Length( p - c ) * Cos( t ); 점은 제품의 벡터의 회전 중심점을 원래 포인트와 벡터의 회전 중심점을 새 지점이 동등한 두 사람은이 제품의 길이가 벡터의 회전과 코사인 각도합니다.
따라서, 새 포인트는 차원의 표면에있는 특정 (d) - 콘;
새 지점을 제한하는 제약 조건 (1) 표면의 특정 (d) - 차원 구체합니다.
(2) 추가 제약 조건을 특정 지점의 새 비행기를 2 - 차원 (d) - 차원 공간을합니다.
따라서, 새 지점이 있어야합니다 - 차원 써클에 따라 특정 (d) - 차원 공간을합니다.
(3) 추가 제약 조건을 특정 지점의 새 (d) - 차원 원뿔합니다.
따라서, 특정 지점의 새 지점에 있어야합니다 (예를 Cos( t ) = 1 또는 Cos( t ) = (-1)) 또는 2 개 지점 중 하나 (예를 (-1) < Cos( t ) < 1).
마지막으로 제약 조건이 필요 포인트 중 하나를 선택하여 그 결과를 제약 조건 위에서 언급한 수있습니다.
어디를 나타냅니다 T(s)로의 "번역" 작업, 어디 (s)은 임의의 벡터, 같은 T(s) * (r) = (r + s), 그리고 Inverse(T(s)) * (r) = (r - s)합니다.
회전 R(S,t,c), 비행기 S, 각도 t, 그리고 중심점 c 수있습니다 측면에서 번역 작업과 표현의 회전을 중심점을 생산지 : R(S,t,c) = T(c) * R(S,t,0) * T(-c) = T(c) * R(S,t,0) * Inverse(T(c))있습니다.
어디 R(S,t) 회전 작업을 나타냅니다 중앙 지점의 회전 (d) - 차원 공간의 기원합니다.
따라서, 임의의 회전으로 표현될 수있습니다 : R(S,t,c) = T(c) * R(S,t) * T(-c) = T(c) * R(S,t) * Inverse(T(c))합니다.
두 개의 회전 비행기 생각해 봅시다 - (S)를 포함하는 차원의 기원은 평행 (d) - 차원 공간과 좌표를 2 축합니다.
(a)을 어디에 (b) 축이 좌표를 나타내는 정수를 (d) - 차원 공간, 같은 0 <= a <= (d-1), 그리고 0 <= b <= (d-1), 그리고 (a != b)합니다.
R(a,b,t) 정의에 대한 우리의 근원을 회전 (d) - 차원 공간 좌표를 회전 비행기가 평행으로 지표 (a) 좌표로 표시하고 (b) 축, 그리고 각도로 (t), 같은 R(a,b,(pi/2)) 좌표 값을는 긍정적인 좌표로 변환 긍정적인 협조에 의해 표시 (a) 축 좌표 축에 표시되는 값을 (b); 예 : R(a,b,(pi/2)) * e(a) = e(b), 어디 e(k) 축 좌표를 나타냅니다 단위 기준에 해당하는 벡터 (k)합니다.
이 정의를 제공합니다 완전하게 확인하는 데 필요한 최종 동음이 제작한 새로운 목표 지점의 회전합니다.
a 축의 회전 방향에 따라 움직임 포인트 b 축 t 각도에 따라 포인트가 이에 상응하는 움직임을 따라 회전하는 축 a하는 방향 축 b 각도 (-t); 즉, R(a,b,t) = R(b,a,(-t))합니다.
만약 (d >= 2), 그럼 차원 공간이 (d) - ((d*(d-1))/2) 쌍의 좌표 축합니다.
따라서, (d >= 2), (d) - 차원 공간이 뚜렷한 ((d*(d-1))/2) 축 - 정렬 회전 비행기합니다.
(예 : d=2 : (x-y 비행기); d=3 : (x-y 비행기, y-z 비행기, z-x 비행기); d=4 : (x-y 비행기, y-z 비행기, z-x 비행기, x-w 비행기, z-w 비행기, 비행기) w-y합니다.)
아래의 코드 매트릭스하는 방법을 보여줍니다 회전 R(a,b,t)를 대변하기 위해 사용할 수있습니다.
은 이러한 예입니다 균질를 사용하는 방식으로 회전을 회전 행렬에서 벡터를 새 동종 동질 벡터합니다.
public class MatrixF64
{
// . . .
public static MatrixF64 Rab( int rows, int a, int b, double angle )
{
if (rows <= 0)
{
// Invalid row count specified.
return (MatrixF64.Zero( 1, 1 ));
}
MatrixF64 result = MatrixF64.Identity( rows );
// If (a==b) (rotate coordinate (a) to (a)), then
// there is no rotation to do.
if ((a != b) && (a >= 0) && (a < rows) && (b >= 0) && (b < rows))
{
double sine = Math.Sin( angle );
double cosine = Math.Cos( angle );
// Override m[a,a] = cosine; m[a,b] = -sine;
// m[b,a] = sine; m[b,b] = cosine;
result[a, a] = cosine;
result[b, b] = cosine;
result[a, b] = (-(sine));
result[b, a] = sine;
}
return (result);
}
public static MatrixF64 Rabk( int rows, int a, int b, int k )
{
double angle = (Math.PI / 2.0) * (double)k;
return (MatrixF64.Rab( rows, a, b, angle ));
}
// . . .
public static void Test()
{
// . . .
// Example of using a homogeneous matrix
// to rotate a homogeneous vector:
// Forming a homogeneous rotation matrix that
// rotates a positive component along coordinate
// axis 0 to a positive component along
// cooridnate axis 1, in 3-dimensional space.
// (The homogeneous matrix must be (3+1)=4
// rows by (3+1)=4 columns.)
MatrixF64 rotation4x4 =
MatrixF64.Rab( 4, 0, 1, (0.5 * Math.PI) );
rotation4x4.WriteLine(3);
// [ 6.12e-17, -1, 0, 0 ]
// [ 1, 6.12e-17, 0, 0 ]
// [ 0, 0, 1, 0 ]
// [ 0, 0, 0, 1 ]
// (The entries '6.12e-17' are negligible.)
// The upper-left 3x3 part of the matrix represents
// a counterclockwise rotation of a quarter-turn
// such that a positive component along axis 0
// would be rotated to a positive component along
// axis 1, in 3-dimensional space.
// Using the homogeneous rotation matrix to
// rotate a homogeneous vector:
VectorF64 homogeneousVector2 =
new VectorF64( 5.0, 6.0, 7.0, 1.0 );
VectorF64 rotatedVector =
rotation4x4 * homogeneousVector2;
rotatedVector.WriteLine();
// ( -6, 5, 7, 1 )
// The relevant vector components (5,6,7) were
// rotated to (-6,5,7), which is consistent with
// a counterclockwise quarter-turn rotation
// with a rotation plane parallel to axes 0 and 1.
// . . .
}
}
3.22 "시계 반대 방향" 제시의 정의
2 - 차원 공간, 분기 - 턴 회전을 e(0) 수있는 벡터 e(1) 변환하는 것은 반대합니다.
회전는 : R(0,1,(pi/2)) * e(0) = e(1)합니다.
따라서, 회전 R(0,1,t)은 시계 반대합니다.
3 - 차원 공간, 분기 - 턴 회전을 e(0)의 벡터로 변환할 수있습니다 반시계 e(1)으로 간주합니다.
분기 - 턴 회전 e(1)의 벡터로 변환할 수있는 e(2)도 반대로 간주합니다.
분기 - 턴 회전 e(2)의 벡터로 변환할 수있는 e(0)도 반대로 간주합니다.
따라서이 반대로 회전 { R(0,1,t), R(1,2,t), R(2,0,t) }합니다.
시계 반대에 대한 정의를 아래에 맞는 부울 수식은 2 - 차원, 3 - 차원 공간 및 연산의 패턴은 일반적인 경우에는 회전 R(a,b,t) :
bool counterClockwise =
(
( (a < b) && (((a + b) % 2) == 1) )
|| ( (a > b) && (((a + b) % 2) == 0) )
);
"시계 반대 방향으로" 회전을 정의합니다 아래에이 규칙을이 :
R(0,1,t),
R(2,0,t), R(1,2,t),
R(0,3,t), R(3,1,t), R(2,3,t),
R(4,0,t), R(1,4,t), R(4,2,t), R(3,4,t),
R(0,5,t), R(5,1,t), R(2,5,t), R(5,3,t), R(4,5,t),
...
3.23 (d) - 차원 공간 : 시계 방향으로 회전
"시계를" 사용하여 이전 섹션에서 정의를 제시, 아래는 "시계 방향으로" 회전 :
R(1,0,t),
R(0,2,t), R(2,1,t),
R(3,0,t), R(1,3,t), R(3,2,t),
R(0,4,t), R(4,1,t), R(2,4,t), R(4,3,t),
R(5,0,t), R(1,5,t), R(5,2,t), R(3,5,t), R(5,4,t),
...
예를 들어, 4 - 차원 공간, 아래의 6 회전 행렬 시계 방향으로 회전 대표 :
R(1,0,t) = Cos(t), Sin(t), 0, 0,
-Sin(t), Cos(t), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
R(0,2,t) = Cos(t), 0, -Sin(t), 0,
0, 1, 0, 0,
Sin(t), 0, Cos(t), 0,
0, 0, 0, 1
R(2,1,t) = 1, 0, 0, 0,
0, Cos(t), Sin(t), 0,
0, -Sin(t), Cos(t), 0,
0, 0, 0, 1
R(3,0,t) = Cos(t), 0, 0, Sin(t),
0, 1, 0, 0,
0, 0, 1, 0,
-Sin(t), 0, 0, Cos(t)
R(1,3,t) = 1, 0, 0, 0,
0, Cos(t), 0, -Sin(t),
0, 0, 1, 0,
0, Sin(t), 0, Cos(t)
R(3,2,t) = 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, Cos(t), Sin(t),
0, 0, -Sin(t), Cos(t)
3.24 (d) - 차원 공간 : 총 개수 축 - 정렬 오리 엔테이션
- 정렬 방향 축의 개수를 명확하게 (d) - 차원 공간은 :
distinctOrientations = Factorial( d ) * IntPow( 2, (d-1) );
이 수식을 지원하는 인수를 아래 단락에 나타납니다.
실험적인 증거를 확인하는 수식은 또한 아래에 제시합니다.
어디 { g(0), g(1), ..., g(d-1) }가 상호 작용하는 일련의 (d) - 수직 단위 벡터 (d) - 차원 공간에서 개체에 연결되어있습니다.
이러한 단위 벡터를 나타냅니다 상대적으로 오리 엔테이션의 개체 (d) - 차원 공간의 좌표 축합니다.
어디에서 "기본 오리 엔테이션의" 개체가 같은 g(i) = e(i), 모든 0 <= i <= (d-1); 각각의 오리 엔테이션 벡터의 객체가 별개의 단위와 관련된 시스템의 기본 벡터의 좌표 (d) - 차원 공간을합니다.
벡터의 개체에 대한 첫 오리 엔테이션 중 하나를 병렬로 (d) 수있습니다 (d) - 차원 공간의 축, 그리고 두 방향 중 하나를 할 수가 상대적으로 축합니다.
따라서, 첫 번째 오리 엔테이션 벡터는 (2 * d) 옵션을합니다.
두 번째 오리 엔테이션 벡터의 개체 중 하나에 평행하게 (d-1) 수있습니다 나머지 축, 2 개 축의 방향이 상대적으로합니다.
따라서, 두 번째 오리 엔테이션 벡터는 (2 * (d-1)) 옵션을합니다.
에서와 같은 방식, 그 다음 오리 엔테이션 벡터는 (2 * (d-2)) 옵션을합니다.
벡터의 최종 오리 엔테이션의 최종 나머지는 강제로 축, 그리고이 두 개의 가능성 중 하나를 강제로 따라하는 방향 축 (를 보존하기 위해 일련의 오리 엔테이션의 패리티 벡터이며 오리 엔테이션 일련의 명령을 결정되어야합니다 상수 벡터 ).