QuantumKatas Superposition Task 12

量子コンピューティングの問題集Microsoft/QuantumKatasでは、Q#プログラムを完成させてユニットテストを実行することにより、問題を解いていくことができます。

今回は、解くのに時間がかかった問題Superposition Task 12について、紹介します。

ユニットテストの実行方法は以下です。(参考: Microsoft Quantum Development Kitのインストール(Linux))

$ cd QuantumKatas/Superposition
$ dotnet test

Task 12

  • 入力
  • ゴール
    • 状態|0...0>から2つのBool型配列が表す等確率の重ね合わせ状態を作る
    • 例) Bool型配列が[false, true, false]と[false, false, true]のとき、(|010> + |001>) / sqrt(2) を作る
  • 前提条件
    • 2つのBool型配列の要素数はどちらもN
    • 2つのBool型配列は、少なくとも1要素は異なる

方針

  1. 最初の量子ビットアダマールゲートを作用させ、 \frac{|0> + |1>}{\sqrt{2}} \bigotimes |0\cdots 0> = \frac{|0\cdots0> + |1\cdots 0>}{\sqrt{2}}を作る
  2. 上で作ったのは2つの状態の重ね合わせ。すなわち、0番目の量子ビットが|0>の状態Aと|1>の状態Bの重ね合わせ。状態Aに配列bits1、状態Bに配列bits2を設定する。
  3. 1番目〜N-1番目の量子ビットをbits1, bits2の要素に応じて反転させる(|0>を|1>にする)。ここで、0番目の量子ビットの状態を判別のために使う。
  4. 最後に残った0番目の量子ビットを設定する。bits1とbits2は、0番目が異なる場合と、1番目〜N-1番目のどれかが異なる場合があることを考慮する。

解答(テストは通った)

    // Task 12. Superposition of two bit strings
    // Inputs:
    //      1) N qubits in |0...0⟩ state
    //      2) two bit string represented as Bool[]s
    // Goal: create an equal superposition of two basis states given by the bit strings.
    //
    // Bit values false and true correspond to |0⟩ and |1⟩ states.
    // Example: for bit strings [false, true, false] and [false, false, true]
    // the qubit state required is (|010⟩ + |001⟩) / sqrt(2).
    // You are guaranteed that the both bit strings have the same length as the qubit array,
    // and that the bit strings will differ in at least one bit.
    operation TwoBitstringSuperposition (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit {
        mutable diffIndex = 0;

        H(qs[0]);

        for (i in 1..Length(qs)-1) {
          if (bits1[i] != bits2[i]) {
            set diffIndex = i;
          }

          if (bits1[i]) {
            (ControlledOnInt(0, X))([qs[0]], qs[i]);
          }

          if (bits2[i]) {
            (ControlledOnInt(1, X))([qs[0]], qs[i]);
          }
        }

        if (diffIndex == 0) {
          if (bits1[0]) {
            X(qs[0]);
          }
        } else {
          if (bits1[0]) {
            if (bits1[diffIndex]) {
              (ControlledOnInt(1, X))([qs[diffIndex]], qs[0]);
            } else {
              (ControlledOnInt(0, X))([qs[diffIndex]], qs[0]);
            }
          }

          if (not bits2[0]) {
            if (bits2[diffIndex]) {
              (ControlledOnInt(1, X))([qs[diffIndex]], qs[0]);
            } else {
              (ControlledOnInt(0, X))([qs[diffIndex]], qs[0]);
            }
          }
        }
    }

ControlledOnInt関数

上記コードではControlledOnInt関数を使いました。

例えば、以下は量子ビットq1, q2, q3が全て状態|1>のとき量子ビットq4にゲートXを作用させます。

 (ControlledOnInt(1, X))([q1, q2, q3], q4);

改良版 (2019/3/31追記)

もっと簡単にできました。ポイントは、状態を識別するための量子ビットを確保して、最後に確保した量子ビットを元に戻すことです。 こちらの記事を参考にさせていただきました。 Microsoft Q# Coding Contest - Winter 2019 - その2 - 純粋関数型雑記帳

    operation TwoBitstringSuperposition (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit {
        using (indicator = Qubit()) {
          H(indicator);

          for (i in 0..Length(qs)-1) {
            if (bits1[i]) {
              (ControlledOnInt(0, X))([indicator], qs[i]);
            }

            if (bits2[i]) {
              (ControlledOnInt(1, X))([indicator], qs[i]);
            }
          }

          (ControlledOnBitString(bits2, X))(qs, indicator);
        }
    }