チュートリアル Linear Algebra Part1解答例


Sample Answers for QuantumKatas Linear Algebra part I
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/LinearAlgebra 

(いきなりこのページに飛んできた人で最初から勉強されたい方はこちらをご参照ください)

ここではQ#による量子プログラミングにあたっての数学的前提知識の学習を行います。
2つ目のチュートリアルは線形代数です。(Linear Algebra=線形代数) Part 1からPart 3までそれぞれのPartに分けて解説します。

(この記事を書くにあたっていろいろ調べていて知ったのですが、現在は高校の数学で行列を学ばないんですね。)

Exercise 1: Matrix addition. (行列の足し算)

まずは行列の足し算です。ここは単純に同じ位置(i, j)にある値を足し合わせるだけなので簡単ですね。

@exercise
def matrix_add(a : Matrix, b : Matrix) -> Matrix:
    # You can get the size of a matrix like this:
    n = len(a)
    m = len(a[0])
    
    # You can use the following function to initialize an n×m matrix filled with 0s to store your answer
    c = create_empty_matrix(n, m)
    
    # You can use a for loop to execute its body several times;
    # in this loop variable i will take on each value from 0 to n-1, inclusive
    for i in range(n):
        # Loops can be nested
        for j in range(m):
            # You can access elements of a matrix like this:
            x = a[i][j]
            y = b[i][j]
            
            # You can modify the elements of a matrix like this:
            c[i][j] = x + y
    
    return c



Exercise 2: Scalar multiplication (行列の整数倍)

行列の整数倍です。これも各成分を整数倍するだけなので簡単にできます。

@exercise
def scalar_mult(x : complex, a : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])    
    c = create_empty_matrix(n, m)
    
    for i in range(n):
        for j in range(m):
            c[i][j] = a[i][j] * x
            
    return c

Exercise 3: Matrix multiplication (行列の掛け算)

行列同士の掛け算です。行列同士の掛け算は行x列で各成分を計算していきます。
@exercise
def matrix_mult(a : Matrix, b : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])
    l = len(b[0])

    
    c = create_empty_matrix(n, l)
    
    for i in range(n):
        for j in range(l):
            for k in range(m):
                x = a[i][k]
                y = b[k][j]
                c[i][j] += x * y
    
    return c


Exercise 4: Matrix Inversion.  (逆行列)

Inverse Matricesとは逆行列のことです。逆行列とはかけると単位行列になる行列のことを言います。
単位行列とはその対角成分に 1 が並んで他は全て 0 となる行列です。
例えば、
\[ \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\
0 & 0 & 1 \\
\end{bmatrix} \] のような行列を言います。
\(I_n\)を単位行列とすると、行列\(A\)の逆行列\(A^{-1}\)は下記のようにあらわせます。
\[AA^{-1} = A^{-1}A = I_n\]

ここでは逆行列を生成してみます。
@exercise
def matrix_inverse(a : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])

    c = create_empty_matrix(n, m)
    d = (a[0][0]*a[1][1] - a[0][1]*a[1][0])

    c[0][0] = a[1][1] / d
    c[0][1] = a[0][1] / d * -1
    c[1][0] = a[1][0] / d * -1
    c[1][1] = a[0][0] / d
    
    return c
参考リンク
https://linear-algebra.com/entry/inverse-matrix
https://mathtrain.jp/inversematrix

Exercise 5: Transpose. (転置行列)

Transposeとは転置行列のことです。転置行列とは行列成分を対角線で折り返した行列のことです。言葉で言うと難しいですが、行列の各要素を添え字\(i, j\)で表した場合、\(i, j\)をひっくり返したものが転置行列になります。 \[A = \begin{bmatrix} x_{0,0} & x_{0,1} & \dotsb & x_{0,m-1} \\ x_{1,0} & x_{1,1} & \dotsb & x_{1,m-1} \\ \vdots & \vdots & \ddots & \vdots \\ x_{n-1,0} & x_{n-1,1} & \dotsb & x_{n-1,m-1} \end{bmatrix}\] Aの転置行列\(A^T\)は \[A^T = \begin{bmatrix} x_{0,0} & x_{1,0} & \dotsb & x_{n-1,0} \\ x_{0,1} & x_{1,1} & \dotsb & x_{n-1,1} \\ \vdots & \vdots & \ddots & \vdots \\ x_{0,m-1} & x_{1,m-1} & \dotsb & x_{n-1,m-1} \end{bmatrix}\] となります。
プログラムで書くと配列の要素番号の入れ替えなので非常に簡単ですね。

@exercise
def transpose(a : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])    
    c = create_empty_matrix(m, n)
    
    for i in range(m):
        for j in range(n):
            c[i][j] = a[j][i]
            
    return c

Exercise 6: Conjugate. (共役行列)

Conjugateは複素数でも出てきましたが、共役(きょうやく)行列のことです。
共役行列とは行列A の成分を複素共役にした行列 A です。
複素共役とは複素数\(a+bi\) (\(a, b\)は実数)に対して虚数部をマイナスにした\(a-bi\)を共役複素数でしたね。(詳しくはこちら)
ここでは共役行列を生成します。
@exercise
def conjugate(a : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])
    
    c = create_empty_matrix(n, m)
    
    for i in range(n):
        for j in range(m):
            c[i][j] = a[i][j].real - a[i][j].imag * 1j
    
    return c

Exercise 7: Adjoint. (随伴行列)

Adjointとは随伴行列のことです。随伴行列とは転置行列+共役行列のことで、行列 A に対して、A の転置およびその成分の複素共役をとったものが随伴行列\(A^\dagger\)(† ダガーと読む、Aのダガーはエーダガー)となります。
つまり、\(A^\dagger = \overline{(A^T)} = (\overline{A})^T\)となります。
随伴行列は\((AB)^\dagger = B^\dagger A^\dagger\)のように計算することができます。

ここでは随伴行列を生成してみます。
@exercise
def adjoint(a : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])

    c = create_empty_matrix(n, m)
    c = transpose(conjugate(a))
    return c

Exercise 8: Unitary Verification (ユニタリー行列)

ユニタリー行列は量子コンピュータにおいて非常に重要です。
ユニタリー行列とは逆行列変換可能でかつその逆行列が随伴行列と一致する行列のことを指します。つまり\(U^{-1} = U^\dagger\)であり\(UU^\dagger = U^\dagger U = I_n\)となります。
下記\(U\)はユニタリー行列の1つの例です。
\[U = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ \frac{i}{\sqrt{2}} & \frac{-i}{\sqrt{2}} \\ \end{bmatrix}\] \[U\dagger = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{-i}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & \frac{i}{\sqrt{2}} \\ \end{bmatrix}\] \[UU\dagger = \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ \frac{i}{\sqrt{2}} & \frac{-i}{\sqrt{2}} \\ \end{bmatrix}\ \begin{bmatrix} \frac{1}{\sqrt{2}} & \frac{-i}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} & \frac{i}{\sqrt{2}} \\ \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \\ \end{bmatrix}\]

ここでは各行列がユニタリー行列かをチェックするプログラムを作成します。
from pytest import approx

@exercise
def is_matrix_unitary(a : Matrix) -> bool:
    n = len(a)

    c = create_empty_matrix(n, n)
    d = create_empty_matrix(n, n)

    c = adjoint(a)

    d = matrix_mult(a,c)
    for i in range(n):
        for j in range(n):
            if i == j:
                if d[i][j] != approx(1):
                    return False
            else:
                if d[i][j] != approx(0):
                    return False
    return True


次はLinear algebra Part 2です。 Go to Part 2