2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,15 +1,32 @@
Suppose that a [[matrix]] <math>M</math> contains [[Arithmetic/Complex|complex numbers]]. Then the [[wp:conjugate transpose|conjugate transpose]] of <math>M</math> is a matrix <math>M^H</math> containing the [[complex conjugate]]s of the [[matrix transposition]] of <math>M</math>.
Suppose that a [[matrix]] <big><math>M</math></big> contains [[Arithmetic/Complex|complex numbers]]. Then the [[wp:conjugate transpose|conjugate transpose]] of <math>M</math> is a matrix <math>M^H</math> containing the [[complex conjugate]]s of the [[matrix transposition]] of <math>M</math>.
: <math>(M^H)_{ji} = \overline{M_{ij}}</math>
::: <big><math>(M^H)_{ji} = \overline{M_{ij}}</math></big>
This means that row <math>j</math>, column <math>i</math> of the conjugate transpose equals the complex conjugate of row <math>i</math>, column <math>j</math> of the original matrix.
In the next list, <math>M</math> must also be a square matrix.
This means that row <big><math>j</math></big>, column <big><math>i</math></big> of the conjugate transpose equals the
<br>complex conjugate of row <big><math>i</math></big>, column <big><math>j</math></big> of the original matrix.
In the next list, <big><math>M</math></big> must also be a square matrix.
* A [[wp:Hermitian matrix|Hermitian matrix]] equals its own conjugate transpose: <math>M^H = M</math>.
* A [[wp:normal matrix|normal matrix]] is commutative in [[matrix multiplication|multiplication]] with its conjugate transpose: <math>M^HM = MM^H</math>.
* A [[wp:unitary matrix|unitary matrix]] has its [[inverse matrix|inverse]] equal to its conjugate transpose: <math>M^H = M^{-1}</math>. This is true [[wikt:iff|iff]] <math>M^HM = I_n</math> and iff <math>MM^H = I_n</math>, where <math>I_n</math> is the identity matrix.
* A [[wp:unitary matrix|unitary matrix]] has its [[inverse matrix|inverse]] equal to its conjugate transpose: <math>M^H = M^{-1}</math>. <br> This is true [[wikt:iff|iff]] <math>M^HM = I_n</math> and iff <math>MM^H = I_n</math>, where <math>I_n</math> is the identity matrix.
Given some matrix of complex numbers, find its conjugate transpose. Also determine if it is a Hermitian matrix, normal matrix, or a unitary matrix.
* MathWorld: [http://mathworld.wolfram.com/ConjugateTranspose.html conjugate transpose], [http://mathworld.wolfram.com/HermitianMatrix.html Hermitian matrix], [http://mathworld.wolfram.com/NormalMatrix.html normal matrix], [http://mathworld.wolfram.com/UnitaryMatrix.html unitary matrix]
<br>
;Task:
Given some matrix of complex numbers, find its conjugate transpose.
Also determine if the matrix is a:
::* Hermitian matrix,
::* normal matrix, or
::* unitary matrix.
;See also:
* MathWorld entry: [http://mathworld.wolfram.com/ConjugateTranspose.html conjugate transpose]
* MathWorld entry: [http://mathworld.wolfram.com/HermitianMatrix.html Hermitian matrix]
* MathWorld entry: [http://mathworld.wolfram.com/NormalMatrix.html normal matrix]
* MathWorld entry: [http://mathworld.wolfram.com/UnitaryMatrix.html unitary matrix]
<br><br>

View file

@ -0,0 +1,30 @@
(defun matrix-multiply (m1 m2)
(mapcar
(lambda (row)
(apply #'mapcar
(lambda (&rest column)
(apply #'+ (mapcar #'* row column))) m2)) m1))
(defun identity-p (m &optional (tolerance 1e-6))
"Is m an identity matrix?"
(loop for row in m
for r = 1 then (1+ r) do
(loop for col in row
for c = 1 then (1+ c) do
(if (eql r c)
(unless (< (abs (- col 1)) tolerance) (return-from identity-p nil))
(unless (< (abs col) tolerance) (return-from identity-p nil)) )))
T )
(defun conjugate-transpose (m)
(apply #'mapcar #'list (mapcar #'(lambda (r) (mapcar #'conjugate r)) m)) )
(defun hermitian-p (m)
(equalp m (conjugate-transpose m)))
(defun normal-p (m)
(let ((m* (conjugate-transpose m)))
(equalp (matrix-multiply m m*) (matrix-multiply m* m)) ))
(defun unitary-p (m)
(identity-p (matrix-multiply m (conjugate-transpose m))) )

View file

@ -0,0 +1,45 @@
import Data.List (transpose)
import Data.Complex
type Matrix a = [[a]]
main :: IO ()
main =
mapM_ (\a -> do
putStrLn "\nMatrix:"
mapM_ print a
putStrLn "Conjugate Transpose:"
mapM_ print (conjTranspose a)
putStrLn $ "Hermitian? " ++ show (isHermitianMatrix a)
putStrLn $ "Normal? " ++ show (isNormalMatrix a)
putStrLn $ "Unitary? " ++ show (isUnitaryMatrix a))
([[[3, 2:+1],
[2:+(-1), 1 ]],
[[1, 1, 0],
[0, 1, 1],
[1, 0, 1]],
[[sqrt 2/2:+0, sqrt 2/2:+0, 0 ],
[0:+sqrt 2/2, 0:+ (-sqrt 2/2), 0 ],
[0, 0, 0:+1]]] :: [Matrix (Complex Double)])
isHermitianMatrix, isNormalMatrix, isUnitaryMatrix :: RealFloat a => Matrix (Complex a) -> Bool
isHermitianMatrix a = a `approxEqualMatrix` conjTranspose a
isNormalMatrix a = (a `mmul` conjTranspose a) `approxEqualMatrix` (conjTranspose a `mmul` a)
isUnitaryMatrix a = (a `mmul` conjTranspose a) `approxEqualMatrix` ident (length a)
approxEqualMatrix :: (Fractional a, Ord a) => Matrix (Complex a) -> Matrix (Complex a) -> Bool
approxEqualMatrix a b = length a == length b && length (head a) == length (head b) &&
and (zipWith approxEqualComplex (concat a) (concat b))
where approxEqualComplex (rx :+ ix) (ry :+ iy) = abs (rx - ry) < eps && abs (ix - iy) < eps
eps = 1e-14
mmul :: Num a => Matrix a -> Matrix a -> Matrix a
mmul a b = [[sum (zipWith (*) row column) | column <- transpose b] | row <- a]
ident :: Num a => Int -> Matrix a
ident size = [[fromIntegral $ div a b * div b a | a <- [1..size]] | b <- [1..size]]
conjTranspose :: Num a => Matrix (Complex a) -> Matrix (Complex a)
conjTranspose = map (map conjugate) . transpose

View file

@ -0,0 +1,52 @@
for [ # Test Matrices
[ 1, 1+i, 2i],
[ 1-i, 5, -3],
[0-2i, -3, 0]
],
[
[1, 1, 0],
[0, 1, 1],
[1, 0, 1]
],
[
[0.707 , 0.707, 0],
[0.707i, 0-0.707i, 0],
[0 , 0, i]
]
-> @m {
say "\nMatrix:";
@m.&say-it;
my @t = @m».conj.&mat-trans;
say "\nTranspose:";
@t.&say-it;
say "Is Hermitian?\t{is-Hermitian(@m, @t)}";
say "Is Normal?\t{is-Normal(@m, @t)}";
say "Is Unitary?\t{is-Unitary(@m, @t)}";
}
sub is-Hermitian (@m, @t, --> Bool) {
so @m».Complex eqv @t».Complex
}
sub is-Normal (@m, @t, --> Bool) {
so mat-mult(@m, @t)».Complex eqv mat-mult(@t, @m)».Complex
}
sub is-Unitary (@m, @t, --> Bool) {
so mat-mult(@m, @t, 1e-3)».Complex eqv mat-ident(+@m)».Complex;
}
sub mat-trans (@m) { map { [ @m[*;$_] ] }, ^@m[0] }
sub mat-ident ($n) { [ map { [ flat 0 xx $_, 1, 0 xx $n - 1 - $_ ] }, ^$n ] }
sub mat-mult (@a, @b, \ε = 1e-15) {
my @p;
for ^@a X ^@b[0] -> ($r, $c) {
@p[$r][$c] += @a[$r][$_] * @b[$_][$c] for ^@b;
@p[$r][$c].=round(ε); # avoid floating point math errors
}
@p
}
sub say-it (@array) { $_».fmt("%9s").say for @array }

View file

@ -0,0 +1,84 @@
use strict;
use English;
use Math::Complex;
use Math::MatrixReal;
my @examples = (example1(), example2(), example3());
foreach my $m (@examples) {
print "Starting matrix:\n", cmat_as_string($m), "\n";
my $m_ct = conjugate_transpose($m);
print "Its conjugate transpose:\n", cmat_as_string($m_ct), "\n";
print "Is Hermitian? ", (cmats_are_equal($m, $m_ct) ? 'TRUE' : 'FALSE'), "\n";
my $product = $m_ct * $m;
print "Is normal? ", (cmats_are_equal($product, $m * $m_ct) ? 'TRUE' : 'FALSE'), "\n";
my $I = identity(($m->dim())[0]);
print "Is unitary? ", (cmats_are_equal($product, $I) ? 'TRUE' : 'FALSE'), "\n";
print "\n";
}
exit 0;
sub cmats_are_equal {
my ($m1, $m2) = @ARG;
my $max_norm = 1.0e-7;
return abs($m1 - $m2) < $max_norm; # Math::MatrixReal overloads abs().
}
# Note that Math::Complex and Math::MatrixReal both overload '~', for
# complex conjugates and matrix transpositions respectively.
sub conjugate_transpose {
my $m_T = ~ shift;
my $result = $m_T->each(sub {~ $ARG[0]});
return $result;
}
sub cmat_as_string {
my $m = shift;
my $n_rows = ($m->dim())[0];
my @row_strings = map { q{[} . join(q{, }, $m->row($ARG)->as_list) . q{]} }
(1 .. $n_rows);
return join("\n", @row_strings);
}
sub identity {
my $N = shift;
my $m = new Math::MatrixReal($N, $N);
$m->one();
return $m;
}
sub example1 {
my $m = new Math::MatrixReal(2, 2);
$m->assign(1, 1, cplx(3, 0));
$m->assign(1, 2, cplx(2, 1));
$m->assign(2, 1, cplx(2, -1));
$m->assign(2, 2, cplx(1, 0));
return $m;
}
sub example2 {
my $m = new Math::MatrixReal(3, 3);
$m->assign(1, 1, cplx(1, 0));
$m->assign(1, 2, cplx(1, 0));
$m->assign(1, 3, cplx(0, 0));
$m->assign(2, 1, cplx(0, 0));
$m->assign(2, 2, cplx(1, 0));
$m->assign(2, 3, cplx(1, 0));
$m->assign(3, 1, cplx(1, 0));
$m->assign(3, 2, cplx(0, 0));
$m->assign(3, 3, cplx(1, 0));
return $m;
}
sub example3 {
my $m = new Math::MatrixReal(3, 3);
$m->assign(1, 1, cplx(0.70710677, 0));
$m->assign(1, 2, cplx(0.70710677, 0));
$m->assign(1, 3, cplx(0, 0));
$m->assign(2, 1, cplx(0, -0.70710677));
$m->assign(2, 2, cplx(0, 0.70710677));
$m->assign(2, 3, cplx(0, 0));
$m->assign(3, 1, cplx(0, 0));
$m->assign(3, 2, cplx(0, 0));
$m->assign(3, 3, cplx(0, 1));
return $m;
}

View file

@ -0,0 +1,76 @@
function conjugate-transpose($a) {
$arr = @()
if($a) {
$n = $a.count - 1
if(0 -lt $n) {
$m = ($a | foreach {$_.count} | measure-object -Minimum).Minimum - 1
if( 0 -le $m) {
if (0 -lt $m) {
$arr =@(0)*($m+1)
foreach($i in 0..$m) {
$arr[$i] = foreach($j in 0..$n) {@([System.Numerics.complex]::Conjugate($a[$j][$i]))}
}
} else {$arr = foreach($row in $a) {[System.Numerics.complex]::Conjugate($row[0])}}
}
} else {$arr = foreach($row in $a) {[System.Numerics.complex]::Conjugate($row[0])}}
}
$arr
}
function multarrays-complex($a, $b) {
$c = @()
if($a -and $b) {
$n = $a.count - 1
$m = $b[0].count - 1
$c = @([System.Numerics.complex]::new(0,0))*($n+1)
foreach ($i in 0..$n) {
$c[$i] = foreach ($j in 0..$m) {
[System.Numerics.complex]$sum = [System.Numerics.complex]::new(0,0)
foreach ($k in 0..$n){$sum = [System.Numerics.complex]::Add($sum, ([System.Numerics.complex]::Multiply($a[$i][$k],$b[$k][$j])))}
$sum
}
}
}
$c
}
function identity-complex($n) {
if(0 -lt $n) {
$array = @(0) * $n
foreach ($i in 0..($n-1)) {
$array[$i] = @([System.Numerics.complex]::new(0,0)) * $n
$array[$i][$i] = [System.Numerics.complex]::new(1,0)
}
$array
} else { @() }
}
function are-eq ($a,$b) { -not (Compare-Object $a $b -SyncWindow 0)}
function show($a) {
if($a) {
0..($a.Count - 1) | foreach{ if($a[$_]){"$($a[$_])"}else{""} }
}
}
function complex($a,$b) {[System.Numerics.complex]::new($a,$b)}
$id2 = identity-complex 2
$m = @(@((complex 2 7), (complex 9 -5)),@((complex 3 4), (complex 8 -6)))
$hm = conjugate-transpose $m
$mhm = multarrays-complex $m $hm
$hmm = multarrays-complex $hm $m
"`$m ="
show $m
""
"`$hm = conjugate-transpose `$m ="
show $hm
""
"`$m * `$hm ="
show $mhm
""
"`$hm * `$m ="
show $hmm
""
"Hermitian? `$m = $(are-eq $m $hm)"
"Normal? `$m = $(are-eq $mhm $hmm)"
"Unitary? `$m = $((are-eq $id2 $hmm) -and (are-eq $id2 $mhm))"

View file

@ -1,87 +1,83 @@
/*REXX pgm performs a conjugate transpose on a complex square matrix. */
parse arg N elements; if N=='' then N=3
M.=0 /*Matrix has all elements equal to zero*/
k=0; do r=1 for N
do c=1 for N; k=k+1; M.r.c=word(word(elements,k) 1,1); end /*c*/
end /*r*/
call showCmat 'M' ,N /*display a nicely formatted matrix. */
identity.=0; do d=1 for N; identity.d.d=1; end /*d*/
call conjCmat 'MH', "M" ,N /*conjugate the M matrix ───► MH */
call showCmat 'MH' ,N /*display a nicely formatted matrix. */
/*REXX program performs a conjugate transpose on a complex square matrix. */
parse arg N elements; if N==''|N=="," then N=3 /*Not specified? Then use the default.*/
k=0; do r=1 for N
do c=1 for N; k=k+1; M.r.c=word(word(elements,k) 1,1); end /*c*/
end /*r*/
call showCmat 'M' ,N /*display a nicely formatted matrix. */
identity.=0; do d=1 for N; identity.d.d=1; end /*d*/
call conjCmat 'MH', "M" ,N /*conjugate the M matrix ───► MH */
call showCmat 'MH' ,N /*display a nicely formatted matrix. */
say 'M is Hermitian: ' word('no yes',isHermitian('M',"MH",N)+1)
call multCmat 'M', 'MH', 'MMH', N /*multiple the two matrices together. */
call multCmat 'MH', 'M', 'MHM', N /* " " " " " */
say ' M is Normal: ' word('no yes',isHermitian('MMH',"MHM",N)+1)
say ' M is Unary: ' word('no yes',isUnary('M',N)+1)
say 'MMH is Unary: ' word('no yes',isUnary('MMH',N)+1)
say 'MHM is Unary: ' word('no yes',isUnary('MHM',N)+1)
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────one─liner subroutines─────────────────────*/
cP: procedure; arg ',' p; return word(strip(translate(p,,'IJ')) 0,1)
rP: procedure; parse arg r ','; return word(r 0,1)
/*────────────────────────────────────────────────────────────────────────────*/
conjCmat: parse arg matX,matY,rows 1 cols; call normCmat matY,rows
do r=1 for rows; _=
do c=1 for cols; v=value(matY'.'r"."c)
rP=rP(v); cP=-cP(v); call value matX'.'c"."r, rP','cP
end /*c*/
end /*r*/
call multCmat 'M', 'MH', 'MMH', N /*multiple the two matrices together. */
call multCmat 'MH', 'M', 'MHM', N /* " " " " " */
say ' M is Normal: ' word('no yes', isHermitian('MMH', "MHM", N) + 1)
say ' M is Unary: ' word('no yes', isUnary('M', N) + 1)
say 'MMH is Unary: ' word('no yes', isUnary('MMH', N) + 1)
say 'MHM is Unary: ' word('no yes', isUnary('MHM', N) + 1)
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
cP: procedure; arg ',' c; return word( strip( translate(c, , 'IJ') ) 0, 1)
rP: procedure; parse arg r ','; return word( r 0, 1) /*◄──maybe return a 0 ↑ */
/*──────────────────────────────────────────────────────────────────────────────────────*/
conjCmat: parse arg matX,matY,rows 1 cols; call normCmat matY, rows
do r=1 for rows; _=
do c=1 for cols; v=value(matY'.'r"."c)
rP=rP(v); cP=-cP(v); call value matX'.'c"."r, rP','cP
end /*c*/
end /*r*/
return
/*────────────────────────────────────────────────────────────────────────────*/
isHermitian: parse arg matX,matY,rows 1 cols; call normCmat matX,rows
call normCmat matY,rows
do r=1 for rows; _=
do c=1 for cols
if value(matX'.'r"."c)\=value(matY'.'r"."c) then return 0
end /*c*/
end /*r*/
return 1
/*────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
isHermitian: parse arg matX,matY,rows 1 cols; call normCmat matX, rows
call normCmat matY, rows
do r=1 for rows; _=
do c=1 for cols
if value(matX'.'r"."c) \= value(matY'.'r"."c) then return 0
end /*c*/
end /*r*/
return 1
/*──────────────────────────────────────────────────────────────────────────────────────*/
isUnary: parse arg matX,rows 1 cols
do r=1 for rows; _=
do c=1 for cols; z=value(matX'.'r"."c); rP=rP(z); cP=cP(z)
if abs(sqrt(rP(z)**2+cP(z)**2)-(r==c))>=.0001 then return 0
end /*c*/
end /*r*/
return 1
/*────────────────────────────────────────────────────────────────────────────*/
multCmat: parse arg matA,matB,matT,rows 1 cols; call value matT'.',0
do r=1 for rows; _=
do c=1 for cols
do k=1 for cols; T=value(matT'.'r"."c); Tr=rP(T); Tc=cP(T)
A=value(matA'.'r"."k); Ar=rP(A); Ac=cP(A)
B=value(matB'.'k"."c); Br=rP(B); Bc=cP(B)
Pr=Ar*Br-Ac*Bc; Pc=Ac*Br+Ar*Bc; Tr=Tr+Pr; Tc=Tc+Pc
call value matT'.'r"."c,Tr','Tc
end /*k*/
end /*c*/
end /*r*/
do r=1 for rows; _=
do c=1 for cols; z=value(matX'.'r"."c); rP=rP(z); cP=cP(z)
if abs(sqrt(rP(z)**2 + cP(z)**2) - (r==c)) >= .0001 then return 0
end /*c*/
end /*r*/
return 1
/*──────────────────────────────────────────────────────────────────────────────────────*/
multCmat: parse arg matA,matB,matT,rows 1 cols; call value matT'.', 0
do r=1 for rows; _=
do c=1 for cols
do k=1 for cols; T=value(matT'.'r"."c); Tr=rP(T); Tc=cP(T)
A=value(matA'.'r"."k); Ar=rP(A); Ac=cP(A)
B=value(matB'.'k"."c); Br=rP(B); Bc=cP(B)
Pr=Ar*Br - Ac*Bc; Pc=Ac*Br + Ar*Bc; Tr=Tr+Pr; Tc=Tc+Pc
call value matT'.'r"."c,Tr','Tc
end /*k*/
end /*c*/
end /*r*/
return
/*────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
normCmat: parse arg matN,rows 1 cols
do r=1 to rows; _=
do c=1 to cols; v=translate(value(matN'.'r"."c),,"IiJj")
parse upper var v real ',' cplx
if real\=='' then real=real/1
if cplx\=='' then cplx=cplx/1; if cplx=0 then cplx=
if cplx\=='' then cplx=cplx"j"
call value matN'.'r"."c,strip(real','cplx,"T",',')
end /*c*/
end /*r*/
do r=1 to rows; _=
do c=1 to cols; v=translate(value(matN'.'r"."c), , "IiJj")
parse upper var v real ',' cplx
if real\=='' then real=real/1
if cplx\=='' then cplx=cplx/1; if cplx=0 then cplx=
if cplx\=='' then cplx=cplx"j"
call value matN'.'r"."c, strip(real','cplx, "T", ',')
end /*c*/
end /*r*/
return
/*────────────────────────────────────────────────────────────────────────────*/
showCmat: parse arg matX,rows,cols; if cols=='' then cols=rows; @@=left('',6)
say; say center('matrix' matX,79,''); call normCmat matX,rows,cols
do r=1 to rows; _=
do c=1 to cols; _=_ @@ left(value(matX'.'r"."c),9); end
/*──────────────────────────────────────────────────────────────────────────────────────*/
showCmat: parse arg matX,rows,cols; if cols=='' then cols=rows; @@=left('',6)
say; say center('matrix' matX, 79, ''); call normCmat matX, rows, cols
do r=1 to rows; _=
do c=1 to cols; _=_ @@ left(value(matX'.'r"."c), 9); end /*c*/
say _
end /*r*/
say; return
/*────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); i=; m.=9
numeric digits 9; numeric form; h=d+6; if x<0 then do; x=-x; i='i'; end
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
numeric digits d; return (g/1)i /*make complex if X < 0.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); numeric form; h=d+6
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2
m.=9; do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g

View file

@ -0,0 +1,80 @@
extern crate num; // crate for complex numbers
use num::complex::Complex;
use std::ops::Mul;
use std::fmt;
#[derive(Debug, PartialEq)]
struct Matrix<f32> {
grid: [[Complex<f32>; 2]; 2], // used to represent matrix
}
impl Matrix<f32> { // implements a method call for calculating the conjugate transpose
fn conjugate_transpose(&self) -> Matrix<f32> {
Matrix {grid: [[self.grid[0][0].conj(), self.grid[1][0].conj()],
[self.grid[0][1].conj(), self.grid[1][1].conj()]]}
}
}
impl Mul for Matrix<f32> { // implements '*' (multiplication) for the matrix
type Output = Matrix<f32>;
fn mul(self, other: Matrix<f32>) -> Matrix<f32> {
Matrix {grid: [[self.grid[0][0]*other.grid[0][0] + self.grid[0][1]*other.grid[1][0],
self.grid[0][0]*other.grid[0][1] + self.grid[0][1]*other.grid[1][1]],
[self.grid[1][0]*other.grid[0][0] + self.grid[1][1]*other.grid[1][0],
self.grid[1][0]*other.grid[1][0] + self.grid[1][1]*other.grid[1][1]]]}
}
}
impl Copy for Matrix<f32> {} // implemented to prevent 'moved value' errors in if statements below
impl Clone for Matrix<f32> {
fn clone(&self) -> Matrix<f32> {
*self
}
}
impl fmt::Display for Matrix<f32> { // implemented to make output nicer
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})\n({}, {})", self.grid[0][0], self.grid[0][1], self.grid[1][0], self.grid[1][1])
}
}
fn main() {
let a = Matrix {grid: [[Complex::new(3.0, 0.0), Complex::new(2.0, 1.0)],
[Complex::new(2.0, -1.0), Complex::new(1.0, 0.0)]]};
let b = Matrix {grid: [[Complex::new(0.5, 0.5), Complex::new(0.5, -0.5)],
[Complex::new(0.5, -0.5), Complex::new(0.5, 0.5)]]};
test_type(a);
test_type(b);
}
fn test_type(mat: Matrix<f32>) {
let identity = Matrix {grid: [[Complex::new(1.0, 0.0), Complex::new(0.0, 0.0)],
[Complex::new(0.0, 0.0), Complex::new(1.0, 0.0)]]};
let mat_conj = mat.conjugate_transpose();
println!("Matrix: \n{}\nConjugate transpose: \n{}", mat, mat_conj);
if mat == mat_conj {
println!("Hermitian?: TRUE");
} else {
println!("Hermitian?: FALSE");
}
if mat*mat_conj == mat_conj*mat {
println!("Normal?: TRUE");
} else {
println!("Normal?: FALSE");
}
if mat*mat_conj == identity {
println!("Unitary?: TRUE");
} else {
println!("Unitary?: FALSE");
}
}

View file

@ -0,0 +1,77 @@
object ConjugateTranspose {
case class Complex(re: Double, im: Double) {
def conjugate(): Complex = Complex(re, -im)
def +(other: Complex) = Complex(re + other.re, im + other.im)
def *(other: Complex) = Complex(re * other.re - im * other.im, re * other.im + im * other.re)
override def toString(): String = {
if (im < 0) {
s"${re}${im}i"
} else {
s"${re}+${im}i"
}
}
}
case class Matrix(val entries: Vector[Vector[Complex]]) {
def *(other: Matrix): Matrix = {
new Matrix(
Vector.tabulate(entries.size, other.entries(0).size)((r, c) => {
val rightRow = entries(r)
val leftCol = other.entries.map(_(c))
rightRow.zip(leftCol)
.map{ case (x, y) => x * y } // multiply pair-wise
.foldLeft(new Complex(0,0)){ case (x, y) => x + y } // sum over all
})
)
}
def conjugateTranspose(): Matrix = {
new Matrix(
Vector.tabulate(entries(0).size, entries.size)((r, c) => entries(c)(r).conjugate)
)
}
def isHermitian(): Boolean = {
this == conjugateTranspose()
}
def isNormal(): Boolean = {
val ct = conjugateTranspose()
this * ct == ct * this
}
def isIdentity(): Boolean = {
val entriesWithIndexes = for (r <- 0 until entries.size; c <- 0 until entries(r).size) yield (r, c, entries(r)(c))
entriesWithIndexes.forall { case (r, c, x) =>
if (r == c) {
x == Complex(1.0, 0.0)
} else {
x == Complex(0.0, 0.0)
}
}
}
def isUnitary(): Boolean = {
(this * conjugateTranspose()).isIdentity()
}
override def toString(): String = {
entries.map(" " + _.mkString("[", ",", "]")).mkString("[\n", "\n", "\n]")
}
}
def main(args: Array[String]): Unit = {
val m = new Matrix(
Vector.fill(3, 3)(new Complex(Math.random() * 2 - 1.0, Math.random() * 2 - 1.0))
)
println("Matrix: " + m)
println("Conjugate Transpose: " + m.conjugateTranspose())
println("Hermitian: " + m.isHermitian())
println("Normal: " + m.isNormal())
println("Unitary: " + m.isUnitary())
}
}