Conjugate transpose: Difference between revisions
Content added Content deleted
(Updated both D entries) |
(jq) |
||
Line 872: | Line 872: | ||
|1 1 0|0 1 0|0 1 1| |
|1 1 0|0 1 0|0 1 1| |
||
+-----+-----+-----+</lang> |
+-----+-----+-----+</lang> |
||
=={{header|jq}}== |
|||
{{works with|jq|1.4}} |
|||
In the following, we use the array [x,y] to represent the complex number x + iy, |
|||
but the following functions also accept a number wherever a complex number is acceptable. |
|||
====Infrastructure==== |
|||
'''(1) transpose/0''': |
|||
If your jq does not have "transpose" then the following may be used: |
|||
<lang jq># transpose/0 expects its input to be a rectangular matrix |
|||
# (an array of equal-length arrays): |
|||
def transpose: |
|||
if (.[0] | length) == 0 then [] |
|||
else [map(.[0])] + (map(.[1:]) | transpose) |
|||
end ;</lang> |
|||
'''(2) Operations on real/complex numbers''' |
|||
<lang jq># x must be real or complex, and ditto for y; |
|||
# always return complex |
|||
def plus(x; y): |
|||
if (x|type) == "number" then |
|||
if (y|type) == "number" then [ x+y, 0 ] |
|||
else [ x + y[0], y[1]] |
|||
end |
|||
elif (y|type) == "number" then plus(y;x) |
|||
else [ x[0] + y[0], x[1] + y[1] ] |
|||
end; |
|||
# x must be real or complex, and ditto for y; |
|||
# always return complex |
|||
def multiply(x; y): |
|||
if (x|type) == "number" then |
|||
if (y|type) == "number" then [ x*y, 0 ] |
|||
else [x * y[0], x * y[1]] |
|||
end |
|||
elif (y|type) == "number" then multiply(y;x) |
|||
else [ x[0] * y[0] - x[1] * y[1], x[0] * y[1] + x[1] * y[0]] |
|||
end; |
|||
# conjugate of a real or complex number |
|||
def conjugate: |
|||
if type == "number" then [.,0] |
|||
else [.[0], -(.[1]) ] |
|||
end;</lang> |
|||
'''(3) Array operations''' |
|||
<lang jq># a and b are arrays of real/complex numbers |
|||
def dot_product(a; b): |
|||
a as $a | b as $b |
|||
| reduce range(0;$a|length) as $i |
|||
(0; . as $s | plus($s; multiply($a[$i]; $b[$i]) ));</lang> |
|||
'''(4) Matrix operations''' |
|||
<lang jq># convert a matrix of mixed real/complex entries to all complex entries |
|||
def to_complex: |
|||
def toc: if type == "number" then [.,0] else . end; |
|||
map( map(toc) ); |
|||
# simple matrix pretty-printer |
|||
def pp(wide): |
|||
def pad: tostring | (wide - length) * " " + .; |
|||
def row: reduce .[] as $x (""; . + ($x|pad)); |
|||
reduce .[] as $row (""; . + "\n\($row|row)"); |
|||
# Matrix multiplication |
|||
# A and B should both be real/complex matrices, |
|||
# A being m by n, and B being n by p. |
|||
def matrix_multiply(A; B): |
|||
A as $A | B as $B |
|||
| ($B[0]|length) as $p |
|||
| ($B|transpose) as $BT |
|||
| reduce range(0; $A|length) as $i |
|||
([]; reduce range(0; $p) as $j |
|||
(.; .[$i][$j] = dot_product( $A[$i]; $BT[$j] ) )) ; |
|||
# Complex identity matrix of dimension n |
|||
def complex_identity(n): |
|||
def indicator(i;n): [range(0;n)] | map( [0,0]) | .[i] = [1,0]; |
|||
reduce range(0; n) as $i ([]; . + [indicator( $i; n )] ); |
|||
# Approximate equality of two matrices |
|||
# Are two real/complex matrices essentially equal |
|||
# in the sense that the sum of the squared element-wise differences |
|||
# is less than or equal to epsilon? |
|||
# The two matrices must be conformal. |
|||
def approximately_equal(M; N; epsilon): |
|||
def norm: multiply(. ; conjugate ) | .[0]; |
|||
def sqdiff( x; y): plus(x; multiply(y; -1)) | norm; |
|||
reduce range(0;M|length) as $i |
|||
(0; reduce range(0; M[0]|length) as $j |
|||
(.; 0 + sqdiff( M[$i][$j]; N[$i][$j] ) ) ) <= epsilon;</lang> |
|||
====Conjugate transposition==== |
|||
<lang jq># (entries may be real and/or complex) |
|||
def conjugate_transpose: |
|||
map( map(conjugate) ) | transpose; |
|||
# A Hermitian matrix equals its own conjugate transpose |
|||
def is_hermitian: |
|||
to_complex == conjugate_transpose; |
|||
# A matrix is normal if it commutes multiplicatively |
|||
# with its conjugate transpose |
|||
def is_normal: |
|||
. as $M |
|||
| conjugate_transpose as $H |
|||
| matrix_multiply($H; $M) == matrix_multiply($H; $M); |
|||
# A unitary matrix (U) has its inverse equal to its conjugate transpose (T) |
|||
# i.e. U^-1 == T; NASC is I == UT == TU |
|||
def is_unitary: |
|||
. as $M |
|||
| conjugate_transpose as $H |
|||
| complex_identity(length) as $I |
|||
| approximately_equal( $I; matrix_multiply($H;$M); 1e-10) |
|||
and approximately_equal( $I ; matrix_multiply($M;$H); 1e-10) ; </lang> |
|||
====Examples==== |
|||
<lang jq>def hermitian_example: |
|||
[ [ 3, [2,1]], |
|||
[[2,-1], 1 ] ]; |
|||
def normal_example: |
|||
[ [1, 1, 0], |
|||
[0, 1, 1], |
|||
[1, 0, 1] ]; |
|||
def unitary_example: |
|||
0.707107 |
|||
| [ [ [., 0], [., 0], 0 ], |
|||
[ [0, -.], [0, .], 0 ], |
|||
[ 0, 0, [0,1] ] ]; |
|||
def demo: |
|||
hermitian_example |
|||
| ("Hermitian example:", pp(8)), |
|||
"", |
|||
("Its conjugate transpose is:", (to_complex | conjugate_transpose | pp(8))), |
|||
"", |
|||
"Hermitian example: \(hermitian_example | is_hermitian )", |
|||
"", |
|||
"Normal example: \(normal_example | is_normal )", |
|||
"", |
|||
"Unitary example: \(unitary_example | is_unitary)" |
|||
; |
|||
demo</lang> |
|||
{{out}} |
|||
<lang sh>$ jq -r -c -n -f Conjugate_transpose.jq |
|||
Hermitian example: |
|||
3 [2,1] |
|||
[2,-1] 1 |
|||
Conjugate transpose: |
|||
[3,-0] [2,1] |
|||
[2,-1] [1,-0] |
|||
Hermitian example: true |
|||
Normal example: true |
|||
Unitary example: true</lang> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |