C言語でPythonのモジュールを自作する

C言語Pythonのモジュールを自作する方法を書く。

環境

参考にしたサイト

1. 準備(virtualenvで実験用環境を作る)

virtualenvコマンドを使って、実験用の環境を作る。virtualenvコマンドを使うとシステムのPython環境と分離した環境が作れる。

まず、virtualenvをインストール。

$ sudo apt install virtualenv

次に、実験用環境mypylibを作って、activateする。 (activateするとプロンプトに(ディレクトリ名)が付く。元の環境に戻るためには$ deactivateを実行。)

$ mkdir mypylib
$ virtualenv --no-site-packages mypylib
$ source mypylib/bin/activate

2. 自作モジュールのC言語ソースを書く

自作モジュールのC言語ソースmypylib/spammodule.cは以下。

#include <Python.h>

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
  const char *command;
  int sts;

  if (!PyArg_ParseTuple(args, "s", &command))
    return NULL;

  sts = system(command);
  return Py_BuildValue("i", sts);
}

static PyMethodDef SpamMethods[] = {
  {"system", spam_system, METH_VARARGS, "Execute a shell command."},
  {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initspam(void)
{
  (void) Py_InitModule("spam", SpamMethods);
}

3. .whlファイル作成用のsetup.pyを用意

.whlファイルを作成するためのmypylib/setup.pyは以下。

from setuptools import setup, Extension

setup(
    name='spam',
    ext_modules=[Extension('spam', sources=['spammodule.c'])]
    )

4. .whlファイル作成

以下のコマンドで.whlファイルを作成する。

(mypylib)$ python setup.py bdist_wheel

mypylib/dist/spam-0.0.0-cp27-cp27mu-linux_x86_64.whlが出来上がる。

5. .whlのインストールと動作確認

作った.whlファイルを実験用環境にインストールする。

(mypylib)$ pip install dist/spam-0.0.0-cp27-cp27mu-linux_x86_64.whl

動作確認。

$ python
Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import spam
>>> status = spam.system("ls -l")

量子コンピューティング向け言語Q#の問題集 QuantumKatas Measurements Task 1.10 ベル状態の識別

Task 1.10は、4つのベル状態を識別する問題です。

解答1

    // Task 1.10. Distinguish four Bell states
    // Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states:
    //         |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
    //         |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
    //         |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
    //         |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
    // Output: 0 if qubits were in |Φ⁺⟩ state,
    //         1 if they were in |Φ⁻⟩ state,
    //         2 if they were in |Ψ⁺⟩ state,
    //         3 if they were in |Ψ⁻⟩ state.
    // The state of the qubits at the end of the operation does not matter.
    operation BellState (qs : Qubit[]) : Int {
      CNOT(qs[0], qs[1]);
      H(qs[0]);

      let q0 = M(qs[0]);
      let q1 = M(qs[1]);

      if (q0 == Zero && q1 == Zero) {
        return 0;
      } elif (q0 == One && q1 == Zero) {
        return 1;
      } elif (q0 == Zero && q1 == One) {
        return 2;
      } else {
        return 3;
      }
    }

解答2

    // Task 1.10. Distinguish four Bell states
    // Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states:
    //         |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
    //         |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
    //         |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
    //         |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
    // Output: 0 if qubits were in |Φ⁺⟩ state,
    //         1 if they were in |Φ⁻⟩ state,
    //         2 if they were in |Ψ⁺⟩ state,
    //         3 if they were in |Ψ⁻⟩ state.
    // The state of the qubits at the end of the operation does not matter.
    operation BellState (qs : Qubit[]) : Int {
      CNOT(qs[0], qs[1]);
      Ry(PI() / 2.0, qs[0]);

      let q0 = M(qs[0]);
      let q1 = M(qs[1]);

      if (q0 == Zero && q1 == Zero) {
        return 1;
      } elif (q0 == One && q1 == Zero) {
        return 0;
      } elif (q0 == Zero && q1 == One) {
        return 3;
      } else {
        return 2;
      }
    }

CNOT(qs[0], qs[1]);(Controlled X)([qs[0]], qs[1]);と同じ。

量子コンピューティング向け言語Q#の問題集 QuantumKatas Superposition Task 15

Superposition Task 15は2日くらい悩んでやっとテストが通った。

Task 15は、次の入力状態からゴール状態を作る問題。

  • 入力状態: N個の量子ビットの状態|0...0> (Nは2の冪乗とは限らない)
  • ゴール状態: W stateという状態、すなわち、 (|10...0> + |010...0> + ... + |0...1>)/sqrt(N)

以下の写真の方針で考えました。

f:id:yabaniyatun:20190403234435j:plain

解答

    // Task 15**. W state on arbitrary number of qubits
    // Input: N qubits in |0...0⟩ state (N is not necessarily a power of 2).
    // Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
    // W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
    // Example: for N = 3, W state is (|100⟩ + |010⟩ + |001⟩) / sqrt(3).
    operation WState_Arbitrary (qs : Qubit[]) : Unit {
      let N = Length(qs);
      Ry(2.0 * ArcCos(Sqrt(ToDouble(N - 1) / ToDouble(N))), qs[0]);
      for (i in 0..N-2) {
        (ControlledOnInt(0, Ry))(qs[0..i], (2.0 * ArcCos(Sqrt(ToDouble(N-i-2)/ToDouble(N-i-1))), qs[i+1]));
      }
    }

QuantumKatas Superposition Task 14

    // And関数を使うためにimport
    open Microsoft.Quantum.Extensions.Bitwise;

    // Task 14**. W state on 2ᵏ qubits
    // Input: N = 2ᵏ qubits in |0...0⟩ state.
    // Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
    // W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
    // Example: for N = 4, W state is (|1000⟩ + |0100⟩ + |0010⟩ + |0001⟩) / 2.
    operation WState_PowerOfTwo (qs : Qubit[]) : Unit {
        // Hint: you can use Controlled modifier to perform arbitrary controlled gates.
        let N = Length(qs);
        let k = Floor(Lg(ToDouble(N)));

        using (qk = Qubit[k]) {
          ApplyToEach(H, qk);

          for (i in 0..N-1) {
            (ControlledOnInt(i, X))(qk, qs[i]);
          }

          for (i in 0..N-1) {
            for (j in 0..k-1) {
              if (And(i, Floor(PowD(2.0, ToDouble(j)))) > 0) {
                (ControlledOnInt(1, X))([qs[i]], qk[j]);
              }
            }
          }
        }
    }

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);
        }
    }

Q#のQuickstartをやってみた

docs.microsoft.com

ファイル構成

  • Bell.qs デバイス側のQ#プログラム。量子ビット(Qubit)に対する操作(operation)を記述。
  • Driver.cs ホスト側のC#プログラム。デバイス側のoperationを呼ぶ。

Bell.qs

namespace Bell {
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Primitive;

    // q1を状態desiredにセットする
    operation Set (desired: Result, q1: Qubit) : Unit {
        // q1の状態を測定(Measurement)
        let current = M(q1);

        if (desired != current) {
          // セットしたい状態と異なる状態ならば反転
          X(q1);
        }
    }

    // countは測定回数。initialはqubits[0]の初期状態。
    operation BellTest (count: Int, initial: Result) : (Int, Int, Int) {
      mutable numOnes = 0;
      mutable agree = 0;
      // 2個のQubitを使う
      using (qubits = Qubit[2]) {
        for (test in 1..count) {
          // qubits[0]を状態initialにセット
          Set(initial, qubits[0]);
          // qubits[1]を|0>にセット
          Set(Zero, qubits[1]);

          // Hはアダマールゲート?
          H(qubits[0]);
          // CNOTゲート?
          CNOT(qubits[0], qubits[1]);
          let res = M(qubits[0]);

          if (M(qubits[1]) == res) {
            set agree = agree + 1;
          }

          // Count the number of ones we saw:
          if (res == One) {
            set numOnes = numOnes + 1;
          }
        }
        Set(Zero, qubits[0]);
        Set(Zero, qubits[1]);
      }

      // Return number of times we saw a |0> and number of times we saw a |1>
      return (count - numOnes, numOnes, agree);
    }
}

Driver.cs

using System;

using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;

namespace Bell
{
    class Driver
    {
        static void Main(string[] args)
        {
            using (var qsim = new QuantumSimulator())
            {
              // Try initial values
              Result[] initials = new Result[] { Result.Zero, Result.One };
              foreach (Result initial in initials) {
                var res = BellTest.Run(qsim, 1000, initial).Result;
                var (numZeros, numOnes, agree) = res;
                System.Console.WriteLine($"Init:{initial,-4} 0s={numZeros,-4} 1s={numOnes,-4} agree={agree,-4}");
              }
            }

            System.Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

実行

$ dotnet run
Init:Zero 0s=508  1s=492  agree=1000
Init:One  0s=470  1s=530  agree=1000
Press any key to continue...

やっていることは、たぶん以下だと思う。

  • 量子ビットを2つ(qubits[0], qubits[1])使う。
  • qubits[0]の初期状態を|0>として、1000回測定した。qubits[0]は|0>が508回、|1>が492回測定された。qubits[0]とqubits[1]は1000回全ての測定で同じ状態だった。
  • qubits[0]の初期状態を|1>として、1000回測定した。qubits[0]は|0>が470回、|1>が530回測定された。qubits[0]とqubits[1]は1000回全ての測定で同じ状態だった。

|0>と|1>の測定回数は実行ごとに変わった。 ゲートHやゲートCNOTが何なのか、不勉強なため、まだわかっていない。

量子コンピューティングのチュートリアル QuantumKatas をやってみようかなぁ。

github.com

C++メモ

コンパイルエラー

$ clang++ test.cpp 
test.cpp:18:6: error: non-const lvalue reference to type 'C' cannot bind to a temporary of type 'C'
  C &c = test();
     ^   ~~~~~~
1 error generated.

上のコンパイルエラーになるソース

#include <cstdio>

class C {
  public:
    C() {}

    void hello() {
      puts("hello");
    }
};

C test() {
  return C();
}

int main(int argc, char* argv[]) {
  C &c = test();
  c.hello();

  return 0;
}

const参照に変更するとコンパイルできる。C::hello()にもconstを付ける。

#include <cstdio>

class C {
  public:
    C() {}

    void hello() const {
      puts("hello");
    }
};

C test() {
  return C();
}

int main(int argc, char* argv[]) {
  const C &c = test();
  c.hello();

  return 0;
}

また、右辺値参照に変更してもコンパイルできる。

#include <cstdio>

class C {
  public:
    C() {}

    void hello() {
      puts("hello");
    }
};

C test() {
  return C();
}

int main(int argc, char* argv[]) {
  C &&c = test();
  c.hello();

  return 0;
}