量子プログラミング入門→量子コンピューティングサービス構築入門

量子コンピューター初心者の筆者が日々学びながら、量子コンピュータ上で量子プログラミングできるようなるまでの学習日記を記録していきます。 内容は量子コンピューター入門者向けで、専門家の方からするとおかしな内容があるかもしれません。その際はコメント等でお知らせください!

カテゴリ:量子ゲート > Q# / Qsharp

Part III. Quantum Algorithm

今回は全4部のうちのPart 3です。

Deutsch-JozsaのTutorialは4部に分かれています。
Part 1: 問題の定義と古典アルゴリズムについて
Part 2: 量子オラクルについて
Part 3: 量子アルゴリズムについて
Part 4: 実際にDeutsch-Jozsaを量子アルゴリズムで動かしてみる

Deutsch–Jozsa Algorithm問題定義

もう一度Deutsch–Jozsaの問題定義をおさらいしておきます。
Deutsch-Jozsaアルゴリズムとは中身のわからないブラックボックスな関数\(f(x)\)について、
1) すべての入力\(x\)に対して、常に0を返す、あるいは、常に1を返す場合、constant
2) 入力\(x\)に対して50%ずつの確率で0と1をそれぞれ返す場合balanced
と関数の性質を判定するアルゴリズムです。

古典コンピューターの場合、関数の性質を判定するのに最悪の場合、総当たり的に入力を与えないと解が求まらないのに対して、量子コンピュータを使うと多項式時間で解が求まることを検証していきます。

Deutsch–Jozsa Algorithm概要

アルゴリズムで実施すること自体はシンプルです。
  1. Apply the H gate to each qubit.
    各ビットにアダマールゲートを適用します。
  2. Apply the oracle.
    量子オラクルを適用します。
  3. Apply the H gate to each qubit again.
    各ビットに再度アダマールゲートを適用します。
  4. Measure each qubits.
    各ビットを測定します。
  5. If all qubits were measured in  |0⟩  state, the function is constant, otherwise it is balanced.
    全ビットが\(|0\rangle\)に読めれば関数\(f(x)\)はconstant, 1つでも\(|1\rangle\)が読めればbalancedと判断
なぜこの手順で判断できるのかを考えてみましょう。

Deutsch–Jozsa Algorithm詳細

1) Apply the H gate to each qubit. 各ビットにアダマールゲートを適用


入力を\(\frac{1}{\sqrt2} \big(|0\rangle + |1\rangle \big)\)の状態に変換する。この形は\(|0\rangle\)と\(|1\rangle\)を同じ確率で取りうる重ね合わせ状態

2Qubitの\(|00\rangle\)にアダマール変換をかけた場合 \[(H \otimes H) |00\rangle = \big(H |0\rangle \big) \otimes \big(H |0\rangle\big) = \left(\frac{1}{\sqrt2} \big(|0\rangle + |1\rangle \big)\right) \otimes \left(\frac{1}{\sqrt2} \big(|0\rangle + |1\rangle \big)\right) = \frac{1}{2} \big(|00\rangle + |01\rangle + |10\rangle + |11\rangle \big)\] となる。これはすべてのbasis stateを同じ確率で重ね合わせた状態である。

これをもとにN-Qubitの場合を考えると
\[ H^{\otimes N} |0\rangle^{\otimes N} = \big( H|0\rangle \big)^{\otimes N} = \left( \frac{1}{\sqrt2} \big(|0\rangle + |1\rangle \big) \right)^{\otimes N} = \frac{1}{\sqrt{2^N}} \sum_{x=0}^{2^N-1} |x\rangle = \frac{1}{\sqrt{2^N}} \big(|0\rangle + |1\rangle + |2\rangle + \ldots +|2^N- 1\rangle \big) = \frac{1}{\sqrt{2^N}} \big(|x_0\rangle \otimes |x_1\rangle \otimes |x_2\rangle \otimes \ldots \otimes |x_N\rangle \big) \]
となる。 
\(\sum\)で書かれると一気によくわからなくなるが、ここは0から\(2^N-1\)までの重ね合わせ状態とばらして考えればよく、各ビットのテンソル積にばらせる場合は0からNビット目までのテンソル積にばらすのと同等と考えてよい。

2) Apply the oracle. 量子オラクルを適用

ここで\(|x\rangle\)にOracleをかける
\[U_f \left(\frac{1}{\sqrt{2^N}} \sum_{x=0}^{2^N-1} |x\rangle \right) = \frac{1}{\sqrt{2^N}} \sum_{x=0}^{2^N-1} U_f|x\rangle = \frac{1}{\sqrt{2^N}} \sum_{x=0}^{2^N-1} (-1)^{f(x)} |x\rangle \]


3) Apply the H gate to each qubit again. 各ビットに再度アダマールゲートを適用


\[ \begin{align}\dfrac{1}{2^N} \sum_{x=0}^{2^N-1} (-1)^{f(x)} \sum_{y=0}^{2^N-1} (-1)^{x \cdot y} \lvert y \rangle = \sum_{y=0}^{2^N-1} \left( \dfrac{1}{2^N} \sum_{x=0}^{2^N-1} (-1)^{f(x)} (-1)^{x \cdot y} \right) \lvert y \rangle\end{align} \]

4) Measure each qubits. 各ビットを測定します。

全N-Qubitを観測して、\({\lvert 0 \rangle ^{\otimes N}}\)が読める確率を考えてみます。
\[\left( \dfrac{1}{2^N} \sum_{x=0}^{2^N-1} (-1)^{f(x)} (-1)^{x \cdot y} \right) \lvert y \rangle^{\otimes N}\]
と考えて、係数の部分に着目し\(|y\rangle={\lvert 0 \rangle ^{\otimes N}}\)=のケースを考えます。
\(x \cdot y\)は\(x\)と\(y\)のBitwise Inner Productで、単純に\(y_N = |0\rangle\)の場合、\(x \times 0\)で0と考えてよいです。つまり、
\[\left( \dfrac{1}{2^N} \sum_{x=0}^{2^N-1} (-1)^{f(x)} \right) \lvert 0 \rangle^{\otimes N}
=\left( \dfrac{1}{2^N} \sum_{x=0}^{2^N-1} (-1)^{f(x)} \right) \left( \lvert 0 \rangle \otimes \lvert 0 \rangle \otimes\ldots \lvert 0 \rangle\right) \]
となり、\(f(x)\)がconstantの場合係数が1または-1、つまり\({\lvert 0 \rangle ^{\otimes n}}\)が読める確率が100%(\(1^2=1, -1^2=1\))、\(f(x)\)がbalancedの場合係数が0、\({\lvert 0 \rangle ^{\otimes N}}\)が読める確率は0%(\(0^2=1\))となります。

Exercise 4: Implement the quantum algorithm!


ここまで来たらあとの実装は簡単だと思います。

operation DeutschJozsaAlgorithm (N : Int, oracle : (Qubit[] => Unit)) : Bool {
    // Create a boolean variable for storing the return value.
    // You'll need to update it later, so it has to be declared as mutable.
    mutable isConstant = true;

    // Allocate an array of N qubits for the input register x.
    using (x = Qubit[N]) {
        // Newly allocated qubits start in the |0⟩ state.
        // The first step is to prepare the qubits in the required state before calling the oracle.
        // A qubit can be transformed from the |0⟩ state to the |+⟩ state by applying a Hadamard gate H.
        ApplyToEach(H, x);

        // Apply the oracle to the input register.
        // The syntax is the same as for applying any function or operation.
        oracle(x);

        // Apply a Hadamard gate to each qubit of the input register again.
        ApplyToEach(H, x);

        // Measure each qubit of the input register in the computational basis using the M operation.
        // You can use a for loop to iterate over the range of indexes 0..N-1.
        // Note that you can't return the answer in the middle of a loop,
        // you have to update the variable isConstant using the "set" keyword.
        for (i in 0 .. N-1) {
            let a = M(x[i]);
            if (a == One) {
                set isConstant = false;
                ResetAll(x);
            }
        }

        // Before releasing the qubits make sure they are all in the |0⟩ state
        // (otherwise you'll get a ReleasedQubitsAreNotInZeroState exception).
        // You can use the library operation Reset which measures a qubit and applies a correction if necessary.
        // The library operation ResetAll does the same for a register of qubits.
        ResetAll(x);
    }
    
    // Return the value of the boolean variable.
    return isConstant;
}



疑問

CNOTゲートは、制御ビットの状態を判断してターゲットビットにNOTをかける操作です。制御ビットとターゲットビットをそれぞれ単独のQubitに分離可能な場合は、簡単に理解できるのですが、Bell Basis\(\frac{1}{\sqrt{2}}\begin{bmatrix} 1 \\ 0 \\ 0 \\ 1 \end{bmatrix}\)のような分離不可能な状態にCNOTをかける場合どのように考えればいいのでしょう?
CNOTゲートの説明を見てるとEntangled(量子もつれ)状態のQubitにもCNOTをかけれると書いてありますが、考え方がよくわかりません。

Experiment with Q# QDK Simulator

とりあえず、Q# QDKのSimulatorを使ってどのように動くかを見てみます。
まず、2 Qubit用意し、ビット0にアダマール変換をかけて、ビット0を制御ビット、ビット1をターゲットビットにしてCNOTをかけることでBell Basisを作ります。

TestOperations.qs
namespace TestOperations
{
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Diagnostics;

    operation EntangledCnot () : Unit {
        using (x = Qubit[2]){
            H(x[0]);
            CNOT(x[0],x[1]); 
	    // 2Qbits are Bell basis and entangled
            DumpRegister((), [x[0]]);
            DumpRegister((), [x[1]]);
            DumpMachine();
	    // 2Qbits are Bell basis and entangled
            CNOT(x[0],x[1]);
            DumpMachine();
            ResetAll(x);
        }
    }
}

最初のCNOTをかけた後に2つのQubitの状態をDumpRegister()とDumpMachineで見てみます。
DumpRegisterはQubitの状態を1ビットずつ見る機能で、DumpMachineは全体のQubitの状態を見る機能です。
この時点で2つのQubitはBell Basisになっており、Bell BasisはEntangled状態なのでDumpRegisterは1Qubitずつに分けて状態を見ることはできないと返ってきます。これは期待通りの動作です。
DumpMachineではBell Basisになっていることを確認できます。
-----DumpRegister---------------->
# wave function for qubits with ids (least to most significant): 0
## Qubits were entangled with an external qubit. Cannot dump corresponding wave function. ##
# wave function for qubits with ids (least to most significant): 1
## Qubits were entangled with an external qubit. Cannot dump corresponding wave function. ##
-----DumpMachine----------------->
# wave function for qubits with ids (least to most significant): 0;1
∣0❭:     0.707107 +  0.000000 i  ==     ***********          [ 0.500000 ]     --- [  0.00000 rad ]
∣1❭:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
∣2❭:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
∣3❭:     0.707107 +  0.000000 i  ==     ***********          [ 0.500000 ]     --- [  0.00000 rad ]


次にこの状態でさらにCNOTをかけてみます。
-----DumpRegister---------------->
# wave function for qubits with ids (least to most significant): 0
∣0❭:     0.707107 +  0.000000 i  ==     ***********          [ 0.500000 ]     --- [  0.00000 rad ]
∣1❭:     0.707107 +  0.000000 i  ==     ***********          [ 0.500000 ]     --- [  0.00000 rad ]
# wave function for qubits with ids (least to most significant): 1
∣0❭:     1.000000 +  0.000000 i  ==     ******************** [ 1.000000 ]     --- [  0.00000 rad ]
∣1❭:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
-----DumpMachine----------------->
# wave function for qubits with ids (least to most significant): 0;1 ∣0❭: 0.707107 + 0.000000 i == *********** [ 0.500000 ] --- [ 0.00000 rad ] ∣1❭: 0.707107 + 0.000000 i == *********** [ 0.500000 ] --- [ 0.00000 rad ] ∣2❭: 0.000000 + 0.000000 i == [ 0.000000 ] ∣3❭: 0.000000 + 0.000000 i == [ 0.000000 ]

そうすると、最初のCNOTをかける前の状態に戻りました。

基本的な考え方 

量子もつれ状態のQubitにCNOTをかける場合は、テンソル積に分解することを考える前にcomputationla basisの足し算に分解します。今回の場合Bell basisは下記のように表現できます。

\[|\psi\rangle = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)\]
この状態にそれぞれCNOTをかけてやります。\(|00\rangle\)では何も起こらず\(|11\rangle\)にはNOTが働くので下記の結果になります。
\[CNOT(\frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)) = \frac{1}{\sqrt{2}}(|00\rangle + |10\rangle) \]




Part I. Problem Statement and Classical Algorithm解説

Deutsch-Jozsaアルゴリズム(ドイチェジョザアルゴリズム)に関するチュートリアルです。Deutsch-Jozsaアルゴリズムは量子コンピューティングの世界では非常に有名なアルゴリズムで、量子コンピューターの有益性を理解するためには良い題材です。ただ実際の世界においてはあまり有効に活用できるようなロジックではないためここでは量子コンピュータの優位性を理解することにフォーカスします。

Deutsch-JozsaのTutorialは4部に分かれています。
Part 1: 問題の定義と古典アルゴリズムについて
Part 2: 量子オラクルについて
Part 3: 量子アルゴリズムについて
Part 4: 実際にDeutsch-Jozsaを量子アルゴリズムで動かしてみる

「Part 1: 問題の定義と古典アルゴリズムについて」は
Deutsch-Jozsaが解決しようとする問題を理解し、古典コンピューターで解こうとした場合の問題点を理解します。

Deutsch–Jozsa Algorithmついて

Deutsch-Jozsaアルゴリズムとは中身のわからないブラックボックスな関数\(f(x)\)について、
1) すべての入力\(x\)に対して、常に0を返す、あるいは、常に1を返す場合、constant
2) 入力\(x\)に対して50%ずつの確率で0と1をそれぞれ返す場合balanced
と関数の性質を判定するアルゴリズムです。

古典コンピューターの場合、関数の性質を判定するのに最悪の場合、全体の51%の入力に対して総当たり的に入力を与えないと解が求まらないのに対して、量子コンピュータを使うと多項式時間で解が求まることを理解します。

Q#の基本的な文法について

この辺りからQ#の基本的な文法についてある程度知っておかないと、if文やfor/whileループの書き方なに戸惑ってしまいます。
Q#の基本的な文法についてはこちらにまとめています。


Exercise 1: Implement a classical function in Q#


Most Significant Bitが0か1かを判定する関数を作成します。

%kata E1_ClassicalFunction_Test 

function Function_MostSignificantBit (x : Int, N : Int) : Int {
    let msb = x >>> (N-1);
    return msb;
}

古典アルゴリズムについて

古典コンピュータの場合、組み合わせを求めるためにループを回す必要があり計算量が\(2^n\)のオーダーになります。実際にプログラムを書いてみて確かめてみましょう。

Exercise 2: Implement the classical algorithm!


ここでは古典コンピュータの古典的なアルゴリズムを使って関数\(f(x)\)がConstantかBalancedかを判定する処理を作ります。ループを\(2^{(n-1)}\)回まわす処理が必要で、前提条件からループが回りきらせる必要はないですが、Constantと判断するには最低でも全入力の51%\((n^{(n/2 +1)}回)\)は試す必要があります。

%kata E2_ClassicalAlgorithm_Test 

operation IsFunctionConstant_Classical (N : Int, f : (Int -> Int)) : Bool {
    mutable ret = true;
    let ret0 = f(0);
    for (i in 1 .. 1 .. (2^N - 1)) {
        let ret_i = f(i);
        if (ret0 != ret_i){
            set ret = false;
            return ret;
        }
    }
    return ret;
}

変数の代入

Q#で変数(mutableな変数)を使用する場合、mutableで宣言する必要があります。
        mutable i = 0;
        set i = 1;
mutableで変数を宣言した後にsetを使用して変数を変更することができます。

letで定義してしまうとimmutableな変数となってしまい、エラーが出ます。
        let i = 0;                                                                      Message ($"{i}");
        set i = 1;

QS6303: An immutable identifier cannot be modified.

メッセージ表示

Q#にはprint, printfやC#にあるConsole.WriteLine関数はありません。
コンソールにメッセージを表示する場合はMessage関数を使います。

準備

"Microsoft.Quantum.Diagnostics"をオープンします。
open Microsoft.Quantum.Diagnostics;

文字列の表示

文字列の表示の場合は単純にMessage関数の引数に文字列を渡します。
Message("test");

変数の値の表示

変数の値を表示する場合文字列の手前に $ を付け、表示したい変数を文字列の中で {}付きで挿入します。.
    let i = 1;
    Message($"Display i={i}");
This shows below.
Display i=1

For ループ

forループの引数の記載の方法は "start .. step .. end"で書きます。
この場合 iは初期値1 から1ずつ増加していき、10まで進みます。
    for (i in 1 .. 1 .. 5 ) {
        Message ($"{i}");
    }

実行結果はこのようになります。
1
2
3
4
5


 


チュートリアル Multi-Qubit Gates解説および解答例

Github
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/MultiQubitGates

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

いよいよ基礎的な学習は最終回です。今回はMulti-Qubit Gatesということで、複数のQubitに対するオペレーションを学習していきます。

Exercise 1: Compound Gate

3Qubitに対するオペレーションを作成します。 8x8の行列で3つのQubitに対する操作を表していますが、これを3つのSingle Qubitに対する操作に分割します。

まず
- 右上のquadrant(4x4)と左下のquadrant(4x4)がゼロになっていること
- 左上のquadrant(4x4)と右下のquadrant(4x4)がiをかけた関係になっていること
に着目し
\[ Q = \begin{bmatrix} 1 & 0 \\ 0 & i \end{bmatrix} \otimes \begin{bmatrix} 0 & -i & 0 & 0 \\ i & 0 & 0 & 0 \\ 0 & 0 & 0 & -i \\ 0 & 0 & i & 0 \end{bmatrix} \]
を導き出します。さらに
- 右上のquadrant(2x2)と左下のquadrant(4x4)がゼロになっていること
- 左上のquadrant(2x2)と右下のquadrant(4x4)が同じになっていること
から
\[ Q = \begin{bmatrix} 1 & 0 \\ 0 & i \end{bmatrix} \otimes \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} \otimes \begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix} = S \otimes I \otimes Y \]
3つのSingle Bitのオペレーションに分解することができました。

%kata T1_CompoundGate_Test

operation CompoundGate (qs : Qubit[]) : Unit is Adj {
    S(qs[0]);
    I(qs[1]);
    Y(qs[2]);
}
(参考)テンソル積の簡単なイメージ \[ \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \otimes \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 1 \cdot \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} & 2 \cdot \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \\ 3 \cdot \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} & 4 \cdot \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \end{bmatrix} \] 

Exercise 2: Preparing a Bell state

CNOTゲートの使い方に関する学習です。CNOTゲートは2Qubitゲートで、最初のビットの状態が\(|1\rangle\)であれば、2Qubit目を反転させます。

解説にあるようにCNOTゲートは量子もつれ状態を作るのに有効です。
\[ \big(\alpha|0\rangle + \beta|1\rangle\big) \otimes |0\rangle = \alpha|00\rangle + \beta|10\rangle \] この状態にCNOTをかけると
\[ \alpha|00\rangle + \beta|11\rangle \] ができます。

ここではBell Stateを作り出すことが目的ですが、Bell Steteは不可分な量子もつれ状態ですので、1Qubitずつの操作に分解することはできません。
\[ \Phi^+ = \frac{1}{\sqrt{2}}\big(|00\rangle + |11\rangle\big) = \frac{1}{\sqrt{2}}\begin{bmatrix} 1 \\ 0 \\ 0 \\ 1
\end{bmatrix} \]

この問題では
\[ \frac{1}{\sqrt{2}}\big(|00\rangle + |10\rangle\big) = \frac{1}{\sqrt{2}}\big(|0\rangle + |1\rangle\big) \otimes |0\rangle \] という状態を作り出しCNOTゲートを適用させます。
\( \frac{1}{\sqrt{2}}\big(|0\rangle + |1\rangle\big) \)はHゲートで作り出すことができますので、HゲートとCNOTゲートで対応できます。
%kata T2_BellState_Test

operation BellState (qs : Qubit[]) : Unit is Adj {
    H(qs[0]);
    CNOT(qs[0],qs[1]);
}

Exercise 3: Swapping two qubits

SWAPゲートも2Qubitに対する同時操作です。仕様もシンプルでチュートリアルの解答はすぐにわかりますが、使用用途がまだよくわかりません。
%kata T3_QubitSwap_Test

operation QubitSwap (qs : Qubit[], index1 : Int, index2 : Int) : Unit is Adj {
    SWAP(qs[index1], qs[index2]);
}

Exercise 4: Controlled Rotation

Controlledは指定した制御ビットの状態を見て、ターゲットビットに操作を加えるオペレーションです。オペレーションはSingle Bitのオペレーションも使用できますしSWAPのような2ビットオペレーションも使用できます。
// Apply X gate to target bit
Controlled
X([control], target);
// Apply SWAP to targets
Controlled
SWAP([control], (q1, q2));
第一引数の制御ビットを[]でくくらないといけないというのにはまりました。制御ビットは配列で複数指定できるのでそのようになっているようです。

%kata T4_ControlledRotation_Test

operation ControlledRotation (qs : Qubit[], theta : Double) : Unit is Adj {
    Controlled Rx([qs[0]], (theta, qs[1]));
}

Exercise 5: Arbitrary controls

ControlledOnBitStringは複数の制御ビットに対して任意(True or False)の判定を行い、条件が一致する場合指定されたオペレーションを実行します。
Q#の文法の説明が少なくてよくわからないですね。
%kata T5_MultiControls_Test

operation MultiControls (controls : Qubit[], target : Qubit, controlBits : Bool[]) : Unit is Adj {
     (ControlledOnBitString(controlBits, X))(controls, target);
}


チュートリアル Multi-Qubit Systems解説および解答例

Githubリンク
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/MultiQubitSystems

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

前回は1Qubitの操作を学んできました、今回は複数Qubit(主に2Qubit)の操作を学習していきます。

ポイント

複数ビットになって数字の数が増えて複雑になっていますが、ここでのポイントは複数ビットの状態は単独ビットのテンソル積の状態に分割可能な場合があり、今回の学習では基本的に分割できる問題ばかりなので、まずは分割してどのような状態にすればよいかを考えていきます。(テンソル積はLinear Algebra Part 2で出てきていますのでお忘れの方はこちらで復習を。)

一般的に書くと下記のようになります。
\[ \begin{bmatrix} \alpha \color{red}\gamma \\ \alpha \color{red}\delta \\ \beta \color{red}\gamma \\ \beta \color{red}\delta \end{bmatrix} = \begin{bmatrix} \alpha \\ \beta \end{bmatrix} \otimes \begin{bmatrix} \color{red}\gamma \\ \color{red}\delta \end{bmatrix} \]


Exercise 1: Show that the state is separable

自分が悩んだポイントを補足しておきます。
\[ \frac{1}{2} \begin{bmatrix} 1 \\ i \\ -i \\ 1 \end{bmatrix} = \begin{bmatrix} ? \\ ? \end{bmatrix} \otimes \begin{bmatrix} ? \\ ? \end{bmatrix} \]
これを上記の一般式に当てはめると
\[ \begin{cases} \alpha\gamma = \frac{1}{2} \\ \alpha\delta = \frac{i}{2} \\ \beta \gamma = \frac{-i}{2} \\ \beta \delta = \frac{1}{2} \\ \end{cases} \]
となります。
さらにこれらを解いていくと \( \frac{\alpha}{\beta} = \frac{-1}{i} = i \) となります。
ここで \( |\alpha|^2 + |\beta|^2 = 1 \)を考慮すると
\[ \alpha = \frac{1}{\sqrt2}, \beta = \frac{-i}{\sqrt2}, \gamma = \frac{1}{\sqrt2}, \delta = \frac{i}{\sqrt2} \] となり解を導くことができます。 問題文には出てきませんが、Qubitの条件 \( |\alpha|^2 + |\beta|^2 = 1 \)を考慮することで解を導くことができます。

いろいろ計算が複雑ですが、ここではヒントもあるのでまずは下記の4つの活用を考えればよいと思います。
\[ \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix},   \begin{bmatrix} 0 \\ 1 \\ 0 \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 0 \\ 1 \end{bmatrix},   \begin{bmatrix} 0 \\ 0 \\ 1 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix},  \begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \end{bmatrix} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \begin{bmatrix} 0 \\ 1 \end{bmatrix} \]

Demo解説

解説を読んでるだけではわからないところも多いので、実際にDemoを動かしてみて理解を深めていきましょう。

量子ビットの配置

Qubitを配列で配置します。初期状態は|00>です。
    // This allocates an array of 2 qubits, each of them in state |0⟩.
    // The overall state of the system is |00⟩
    using (qs = Qubit[2]) {
つまり
\[ \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} \]
という状態です。

1Qubit目の反転

qs[0]=1ビット目をXゲートで反転させます。
        // X gate changes the first qubit into state |1⟩
        // The entire system is now in state |10⟩
        X(qs[0]);
\[ \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} \]
の状態の1ビット目を反転させるので
\[ \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 1\\ 0 \\ 0 \end{bmatrix}  \]
になります。
結果は
System in state |10⟩ = |1⟩:
# wave function for qubits with ids (least to most significant): 0;1
∣0❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣1❭:	 1.000000 +  0.000000 i	 == 	******************** [ 1.000000 ]     --- [  0.00000 rad ]
∣2❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣3❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]        
コメントが"System in state |10⟩ = |1⟩:"になっていますが、"System in state |10⟩ = |10⟩:"のほうが正確ですかね。

アダマールゲート適用

2ビット目にアダマールゲートを適用します。
        // This changes the second qubit into state |+⟩ = (1/sqrt(2))(|0⟩ + |1⟩).
        // The entire system is now in state (1/sqrt(2))(|10⟩ + |11⟩)
        H(qs[1]);
\[ \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \\ 1 \\ 0 \end{bmatrix}  \]
の状態の2ビット目にHゲートを適用するので2ビット目が
\( H|1\rangle = |+\rangle = \frac{1}{\sqrt{2}}\big(|0\rangle + |1\rangle\big) \)
となり
\[ \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \frac{1}{\sqrt{2}} \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \frac{1}{\sqrt{2}}\begin{bmatrix} 0 \\ 1 \\ 0 \\ 1 \end{bmatrix}  \]
となります。
System in state (1/sqrt(2))(|10⟩ + |11⟩) = (1/sqrt(2))(|1⟩ + |3⟩):
# wave function for qubits with ids (least to most significant): 0;1
∣0❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣1❭:	 0.707107 +  0.000000 i	 == 	***********          [ 0.500000 ]     --- [  0.00000 rad ]
∣2❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣3❭:	 0.707107 +  0.000000 i	 == 	***********          [ 0.500000 ]     --- [  0.00000 rad ]

1ビット目にもアダマールゲート適用

1ビット目は|1>なので|->になるので、
        // This changes the first qubit into state |-⟩ = (1/sqrt(2))(|0⟩ - |1⟩)
        // The entire system is now in state 0.5(|00⟩ + |01⟩ - |10⟩ - |11⟩)
        H(qs[0]);
\[ \frac{1}{\sqrt{2}} \begin{bmatrix} 1 \\ -1 \end{bmatrix} \otimes \frac{1}{\sqrt{2}} \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \frac{1}{2}\begin{bmatrix} 1 \\ -1 \\ 1 \\ -1 \end{bmatrix}  \]
となります。
System in state 0.5(|00⟩ + |01⟩ - |10⟩ - |11⟩) = 0.5(|0⟩ + |2⟩ - |1⟩ - |3⟩):
# wave function for qubits with ids (least to most significant): 0;1
∣0❭:	 0.500000 +  0.000000 i	 == 	******               [ 0.250000 ]     --- [  0.00000 rad ]
∣1❭:	-0.500000 +  0.000000 i	 == 	******               [ 0.250000 ] ---     [  3.14159 rad ]
∣2❭:	 0.500000 +  0.000000 i	 == 	******               [ 0.250000 ]     --- [  0.00000 rad ]
∣3❭:	-0.500000 +  0.000000 i	 == 	******               [ 0.250000 ] ---     [  3.14159 rad ]  

量子もつれの生成

ここまではQubitを分解してそれぞれのQubitの状態を変化させテンソル積で複数Qubitの状態を表してきましたが、ここではEntangle状態(分割不可)の状態を作り出します。
1ビットずつの操作ではなく2ビットまとめて操作することでEntangle状態を作り出すことができます。
        // The next lines entangle the qubits.
        // Don't worry about what exactly they do for now
        H(qs[1]);
        CNOT(qs[0], qs[1]);
CNOTゲートはのちのチュートリアルで出てくるのでここでは細かい説明を省略しますが、1ビット目の状態を見て、2ビット目を反転させる処理になります。
Entangled state 0.5(|00⟩ - |11⟩):
# wave function for qubits with ids (least to most significant): 0;1
∣0❭:	 0.707107 +  0.000000 i	 == 	***********          [ 0.500000 ]     --- [  0.00000 rad ]
∣1❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣2❭:	 0.000000 +  0.000000 i	 == 	                     [ 0.000000 ]                   
∣3❭:	-0.707107 +  0.000000 i	 == 	***********          [ 0.500000 ] ---     [  3.14159 rad ]
この状態はExercise 2で出てきた不可分な状態(量子もつれ状態)ですね。

Exercise 3: Prepare a basis state

デモの内容が理解できれば簡単だと思います。
初期状態は分解可能なので
\( \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix} =
\begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\ 0 \end{bmatrix} \) から  \( \begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \end{bmatrix} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \otimes \begin{bmatrix} 0 \\ 1 \end{bmatrix} \)
を作り出します。 それぞれのビットを反転させるだけですね。
%kata T1_PrepareState1_Test

operation PrepareState1 (qs : Qubit[]) : Unit is Adj+Ctl {
    X(qs[0]);
    X(qs[1]);
}

Exercise 4: Prepare a superposition of two basis states

ヒントをみて
\[ |0\rangle \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\ -1 \end{bmatrix} \]
を作り出すことを理解すればそれほど難しくありません。
2ビット目を\(|-\rangle \)にすればよいので、Xゲート、Hゲートの順に適用します。
%kata T2_PrepareState2_Test

operation PrepareState2 (qs : Qubit[]) : Unit is Adj+Ctl {
    X(qs[1]);
    H(qs[1]);
}

Exercise 5: Prepare a superposition with real amplitudes

この問題もヒントをみて
\[ \frac{1}{\sqrt2}\big(|0\rangle + |1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\ 1 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\ -1 \end{bmatrix} \]
を作り出すことがわかれば簡単です。2ビット目は先ほどのExercise 4と同じなので1ビット目を \(|+\rangle \) にするためにHゲートを適用します。
%kata T3_PrepareState3_Test

operation PrepareState3 (qs : Qubit[]) : Unit is Adj+Ctl {
    H(qs[0]);
    X(qs[1]);
    H(qs[1]);
}

Exercise 6: Prepare a superposition with complex amplitudes

ヒントに書かれていることを導き出すのが難しいかもしれませんが、ヒントがあるのでヒントに書かれていることを実装すればよいです。それぞれ\(|+\rangle \)にSゲート、Tゲートを適用すればよいです。
%kata T4_PrepareState4_Test

operation PrepareState4 (qs : Qubit[]) : Unit is Adj+Ctl {
    H(qs[0]);
    S(qs[0]);
    H(qs[1]);
    T(qs[1]);
}


チュートリアル Single-Qubit Gates解答例

Githubリンク
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/SingleQubitGates

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

このチュートリアルは実際にQ#を使ってQubitの値を操作していきます。古典コンピュータで言うAND, OR, ビットシフトみたいな位置づけだと思いますが、古典コンピュータよりもけっこう複雑ですね。

Exercise 1: The  𝑌  gate

α|0> + β|1>にYゲートを適用します。
これはそのままですね。戻り値はUnitなので何も戻す必要がありません。

%kata T1_ApplyY_Test

operation ApplyY (q : Qubit) : Unit is Adj+Ctl {
    Y(q);
}

Exercise 2: Applying a global phase  𝑖

これも実は本チュートリアルにあるDemoの動き通りですね。
XYZゲートの動きをきちんと理解しましょう。
%kata T2_GlobalPhaseI_Test

operation GlobalPhaseI (q : Qubit) : Unit is Adj+Ctl {
    X(q);
    Z(q);
    Y(q);
}

Exercise 3*: Applying a  −1  phase to  |0⟩  state

XYZゲートの動きを理解して、何を組み合わせれば目的のα=-1とβ=1を導けるかを考えます。
%kata T3_SignFlipOnZero_Test

operation SignFlipOnZero (q : Qubit) : Unit is Adj+Ctl {
    X(q);
    Z(q);
    X(q);
}

Exercise 4: Preparing a  |−⟩  state

前回のQubitで紹介しましたが\( i = \ e^{i\pi/2}  \)なので、Sゲートは\( \pi/2 \)ずつPhaseをずらしていきます。順に適用していくと |+> ⇒ |-> ⇒ |i> ⇒ |-i> ⇒ |+> という順に状態が変化します。こちらを理解していれば簡単です。
まずは|0>から|+>を作るためにHゲートを使用し、あとはシフトさせていきます。
%kata T4_PrepareMinus_Test

operation PrepareMinus (q : Qubit) : Unit is Adj+Ctl {
    H(q);
    S(q);
    S(q);
}

Exercise 5: Three-fourths phase

Phase Shiftゲートの動きを理解しましょう。
%kata T5_ThreeQuatersPiPhase_Test

operation ThreeQuatersPiPhase (q : Qubit) : Unit is Adj+Ctl {
    S(q);
    T(q);
}

理論上は下記でも同等です。
\[ e^{i\pi/4} = \frac{1}{\sqrt{2}} + \frac{i}{\sqrt{2}} \\ e^{i\pi/2} = i \\ e^{i\pi} = -1 \\ e^{2i\pi} = 1 \]
であることを考えると、Tゲート2回とSゲート1回が同等となります。
%kata T5_ThreeQuatersPiPhase_Test

operation ThreeQuatersPiPhase (q : Qubit) : Unit is Adj+Ctl {
    T(q);
    T(q);
    T(q);
}

Exercise 6: Preparing a rotated state


回転系のGateに入って少し雰囲気が変わりますが、R系のGateの定義をきちんと読めばそれほど難しくありません。|0>から目的の\( \alpha|0\rangle -i\beta|1\rangle \)を作り出すためには\( R_x() \)を使います。
今回初めてQ#での変数の代入処理が発生しますが、チュートリアルに書いてある通り、
let num = function();
という形で代入することができます。

%kata T6_PrepareRotatedState_Test

open Microsoft.Quantum.Math;

operation PrepareRotatedState (alpha : Double, beta : Double, q : Qubit) : Unit is Adj+Ctl {
    let theta = ArcTan2(beta, alpha) * 2.0;
    Rx(theta, q);
}

Exercise 7**: Preparing an arbitrary state


次は回転系のゲートの組み合わせです。R系ゲートの定義をきちんと読めば\(R_y\)と\(R_1\)の組み合わせで実現可能なことがわかります。
\( \beta = \sqrt{1 - \alpha^2} \)という書き方をしていますが、\( \alpha^2 + \beta^2 = 1 \)と同義ですよね。何かのヒントなのかもしれませんが意図が理解できてません。

%kata T7_PrepareArbitraryState_Test

open Microsoft.Quantum.Math;

operation PrepareArbitraryState (alpha : Double, beta : Double, theta : Double, q : Qubit) : Unit is Adj+Ctl {
    let theta1 = ArcTan2(beta, alpha) * 2.0;
    Ry(theta1, q);
    R1(theta, q);
}



Qubit解説

Github
https://github.com/microsoft/QuantumKatas/blob/49f4e543167be2875ea4c293cd12771383828462/tutorials/Qubit/Qubit.ipynb


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

数学的前提知識の学習が終わっていよいよ量子っぽい話になりました。
Qubitはexerciseがないので解説だけになります。

古典コンピュータではBitが基本的な構成要素となっている。
量子コンピューターにおいてはqubitが基本的な構成要素となる
bitは0と1の二値を持つことができる。

qubitは観測した際にはZero(|0>)もしくはOne(|1>)のどちらかの値が測定できるが、
実際にはsuperposition(量子重ね合わせ)によりより多くの値を持つことができる。
|0>と|1>は単純なスカラではなくそれぞれ下記のベクトルで表現される
\[ |0> = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \] \[ |1> = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \]
この|0>と|1>の状態をcomputational basis, または the canonical basisと呼ぶ

ZeroとOneが読める確率を表現するために確率振幅αとβを用いる。αをZeroのための係数、βをOneのための係数とし、qubitの状態は下記の表現で表せる
\[ \alpha \cdot \begin{bmatrix} 1 \\ 0 \end{bmatrix} + \beta \cdot \begin{bmatrix} 0 \\ 1 \end{bmatrix} = \begin{bmatrix} \alpha \\ 0 \end{bmatrix} + \begin{bmatrix} 0 \\ \beta \end{bmatrix} = \begin{bmatrix} \alpha \\ \beta \end{bmatrix} \] 

このαとβの確率振幅は下記の条件を満たす。
\[|\alpha|^2 + |\beta|^2 = 1\] 

常に|0>が読めるような状態は\[\alpha=1, \beta = 0\] 
常に|1>が読めるような状態は\[\alpha=0, \beta = 1\] 
となる。

なんとなくイメージはわかるが、だからなんなのかよくわからん....
とりあえずそういうものなんだと丸暗記しておく。


Hadamard basis(アダマール基底)というのも先々使いそうなのでとりあえずそういうものだと覚えておく。
\[ \begin{bmatrix} \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{bmatrix} \text{ and } \begin{bmatrix} \frac{1}{\sqrt{2}} \\ -\frac{1}{\sqrt{2}} \end{bmatrix} \]

Dirac Notation(ブラ・ケット記法)
これらのベクトルをより簡易に表現するための記法。
\[ |0\rangle = \begin{bmatrix} 1 \\ 0 \end{bmatrix}  \text{ and }  |1\rangle = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \]

|+>, |->, |i>, |-i>は一般的に下記の意味で用いられる
\[ |+\rangle = \frac{1}{\sqrt{2}}\big(|0\rangle + |1\rangle\big) \] \[ |-\rangle = \frac{1}{\sqrt{2}}\big(|0\rangle - |1\rangle\big) \]
\[ |i\rangle = \frac{1}{\sqrt{2}}\big(|0\rangle + i|1\rangle\big) \] \[ |-i\rangle = \frac{1}{\sqrt{2}}\big(|0\rangle - i|1\rangle\big) \]

Q#でのQubitデータ型

Qubit型

  • Q#でqubitを表すためにQubit型が使われる。
  • 物理的な量子コンピュータではqubitの正確な状態を直接読んだり、直接状態を変更したりすることはできないが、量子ゲートを使用することによりこれらの値を変更したり測定することがことができる。
  • The qubitは通常のデータ型ではないため、使用前に宣言する必要がある
  • 宣言された直後のqubitは|0>であり、そのブロックが終了するまでは|0>であり続ける。

// This statement allocates a qubit, and binds it to the variable q
using (q = Qubit()) {
    // You can work with the qubit here
    // ...
}
// The qubit is no longer allocated outside of the 'using' block

Q#のQubitオペレーション

ここのDemoで使われるオペレーションはこちらで説明されているが、読むだけではよくわからないのでいろいろ動かしてみる。このあたりは古典コンピューターで言うANDとORとかBit Shiftとか基礎中の基礎なのかなと思う。

X ゲート

|0⟩ と |1⟩ の状態を入れ替える
|0>が読める状態なら|1>に、|1>が読める状態なら|0>変換する。
\[ {\sigma_x = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} } \]
        // This line changes the qubit from state |0⟩ to state |1⟩
        X(q);

Hゲート(アダマール ゲート)

与えられた量子ビットに対してアダマール変換をかけます。
アダマールゲートの使い方として、|0>か|1>が100%観測される状態から、0か1の確率が全く等しい量子ビットを生成する。またHゲートを一度適用した状態からもう一度適用すると元の状態に戻すことができる。
\[ {H = \frac{1}{\sqrt 2} \begin{pmatrix} 1&1 \\ 1&-1 \end{pmatrix} } \]
        // This line changes the qubit to state |-⟩ = (1/sqrt(2))(|0⟩ - |1⟩)
        // That is, this puts the qubit into a superposition
        // 1/sqrt(2) is approximately 0.707107
        H(q);

S (ゲート)

π/2ずつ回転させていく、回転というとよくわからないが、|+>に適用すると |->になる。
順に適用していくと
|+> ⇒ |-> ⇒ |i> ⇒ |-i> ⇒ |+>
という順に状態が変化する。(上記の表の時計回りに状態が遷移)
\[ {S = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix} } \]
	// This line changes the qubit to state |-i⟩ = (1/sqrt(2))(|0⟩ - i|1⟩)
        S(q);

(執筆時点で)
MSのリファレンスではSゲートは
"Applies the π/4 phase gate to a single qubit."とあるが、 \( i = \ e^{i\pi/2}  \)なので、Sゲートは\( \pi/2 \)ずつ回転の間違い
Tゲートも"Applies the π/8 gate to a single qubit."とあるが \( \pi/8 \)ではなく \( \pi/4 \)の間違いですね。

\( 2 \pi =360\degree \)なので \( \pi/2 \)を4回適用して1周回る感じですね。

ウィキペディア参照

R (ローテーションゲート)

\[ R_x : x軸に与えられた角度を加える。 \] 
\[ R_y : y軸に与えられた角度を加える。 \]
よくわからないが、ブロッホ球の任意の場所にベクトルを向ける際に使うqubit操作なのかなと想像しておく
        // This will put the qubit into an uneven superposition,
        // where the amplitudes of |0⟩ and |1⟩ have different moduli
        Rx(2.0, q);
        Ry(1.0, q);

x,y,zの回転軸の説明はこちらにあります。


icon




これらの関数ももう少し使い込んでみれば、どういうときに有効なのがわかってくると期待している。


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

Linear Algebra=線形代数
Sample Answers for QuantumKatas Linear Algebra part I
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/LinearAlgebra 

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

ここではQ#による量子プログラミングにあたっての数学的前提知識の学習を行います。
前提知識の学習はPart 3がいよいよ最後です。

Eigenvalue: 固有値
Eigenvector: 固有ベクトル

Exercise 13: Finding an eigenvalue

固有値を求める
固有ベクトルはゼロベクトルではないので、2つの行列を掛け算し、結果をVのゼロでない要素で割り算すれば求まります。
@exercise

def find_eigenvalue(a : Matrix, v : Matrix) -> float:

    n = len(v)
    x = matrix_mult(a, v)

    for i in range(n):
        if v[i][0] ==0:
            continue
        else:
            return x[i][0] / v[i][0]


Exercise 14**: Finding an eigenvector

固有ベクトルを求める。固有ベクトルの求め方については下記リンクを参照
https://to-kei.net/linear-algebra/eigenvalue/eigenvalue-and-eigenvector/

行の要素がオールゼロの場合は別の行を選択する必要があります。

@exercise
def find_eigenvector(a : Matrix, x : float) -> Matrix:
    v = create_empty_matrix(2, 1)
    if a[0][0] == 0 and a[1][0] == 0:
        v[0][0] = 0
        v[1][0] = a[1][1] / x
    elif a[1][0] == 0 and a[1][1] == 0:
        v[0][0] = a[0][0] / x
        v[1][0] = 0
    else:
        v[0][0] = a[0][1]
        v[1][0] = x - a[0][0]

    return v



いよいよ次は基本的な数学の準備から抜け出して、量子ビット(Qubit)について学習していきます。






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


Linear Algebra=線形代数
Sample Answers for QuantumKatas Linear Algebra part I
https://github.com/microsoft/QuantumKatas/tree/master/tutorials/LinearAlgebra 

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

ここではQ#による量子プログラミングにあたっての数学的前提知識の学習を行います。
Part 2は内積・外積などを学習します。

Exercise 9: Inner product. (行列の内積)

行列の内積(スカラー積)

@exercise
def inner_prod(v : Matrix, w : Matrix) -> complex:
    n = len(v)
    
    c = create_empty_matrix(n, 0)
    c = conjugate(v)
    
    x = 0 + 0j
    for i in range(n):
        x =x + c[i][0] * w[i][0]

    return(x)


Exercise 10: Normalized vectors

単位ベクトルの生成

@exercise
def normalize(v : Matrix) -> Matrix:
    n = len(v)
    m = len(v[0])
    
    w = inner_prod(v, v)
    a = math.sqrt(w.real)
    c = create_empty_matrix(n, m)

    for i in range(n):
        c[i][0] = v[i][0] / a

    return c


Exercise 11: Outer product

行列の外積(ベクトル積)
mは変数にしなくても1でハードコーディングでよいです。
@exercise
def outer_prod(v : Matrix, w : Matrix) -> Matrix:
    n = len(v)
    m = len(w)    

    c = create_empty_matrix(m, 0)
    c = conjugate(w)

    d = create_empty_matrix(n, m)
    for i in range(n):
        for j in range(m):
            d[i][j] = v[i][0] * c[j][0]
    return(d)

Exercise 12*: Tensor Product.

テンソル積
出来上がる行列のインデックスをきちんと考えればそれほど難しい問題ではないですね。

@exercise
def tensor_product(a : Matrix, b : Matrix) -> Matrix:
    n = len(a)
    m = len(a[0])    
    k = len(b)
    l = len(b[0])

    c = create_empty_matrix(n * k, m * l)
    for ia in range(n):
        for ja in range(m):
            for ib in range(k):
                for jb in range(l):
                    c[ia*k+ib][ja*l+jb] = a[ia][ja]*b[ib][jb]
    return c




次はLinear Algebra Part 3です。Go to Part 3



↑このページのトップヘ