Q#でのコードの実行方法でいろいろわからなかったので,メモしておきます.codeforcesのコンテストにおけるsolve関数のテスト方法についてもメモしました.
単純なHello Quantum Worldのやりかた
1.まずは新しい自分が作りたいソリューションファイルをつくります.
2. Ctrl+Shift+Nで新しいプロジェクトをつくって,QSharpApplicationの新しいプロジェクトを作成しました.
QSharpApplication1を右クリックして,「スタートアッププロジェクトに設定」をクリックします.これでF5キーで実行できるようになります.
書いたqsファイルをそもそも実行する方法がわからなかったのでメモします.
もともと作成されているDriver.csに,以下のように追記します.
using System;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace Quantum.QSharpApplication1
{
class Driver
{
static void Main(string[] args)
{
using (var qsim = new QuantumSimulator())
{
HelloQ.Run(qsim).Wait();
}
System.Console.ReadLine(); //ここを追記してhello quantum worldが表示されます
}
}
}
ここができても量子プログラミングのおいては特に意味はありません.
どうやってoperationを実行すればいいのか?
Qubitの用意の仕方
公式リファレンスをみて学んでいくことにします.
公式では以下のファイルを作成することになります.
using System;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
using System.Linq;
using Microsoft.Quantum.Simulation;
namespace Quantum.QSharpApplication1
{
class Driver
{
public static void Pause()
{
System.Console.WriteLine("\n\nPress any key to continue...\n\n");
System.Console.ReadKey();
}
static void Main(string[] args)
{
using (var qsim = new QuantumSimulator())
{
// Try initial values
Result[] initials = new Result[] { Result.Zero, Result.One };//initialsがzeroかoneかで2つ分実行する
foreach (Result initial in initials)
{
var res = BellTest.Run(qsim, 1000, initial).Result;//BellTest.Runはqsimと,2つの引数が必要
var (numZeros, numOnes, agree) = res; //BellTestが3つの引数を返す
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();
}
}
}
qsファイルの,operation部分を抜き出したものが以下です.
//この関数でqubitをsetする
operation Set (desired: Result, q1: Qubit) : Unit
{
let current = M(q1);
if (desired != current)
{
X(q1);
}
}
operation BellTest (count : Int, initial: Result) : (Int, Int, Int)
{
mutable numOnes = 0;
mutable agree = 0;
using (qubits = Qubit[2]) //qubitsの宣言はこのように行う
{
for (test in 1..count)
{
Set (initial, qubits[0]);//initialのZero,Oneにあわせて,qubits[0]をsetする
Set (Zero, qubits[1]);//qubits[1]はzeroでセットする
H(qubits[0]);
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);
}
公式を読めば,その後の作業としては,エンタングル状態を作った時の測定がどうなるかプログラムできる,という内容のことまで書いてあります.サンプルを読めば大体どんな感じに書けばいいかもイメージがついてきます.
qs内でusing()で宣言すれば,Qubitを用意できるようです.|0>で初期化されています.
Solve関数のテスト方法
そのままだとテストができないのでどうするか戸惑いました.
QubitをDriver.csで書くのかどこで宣言するか,などについては以下の記事がわかりやすかったです.
https://tech.tanaka733.net/entry/2018/07/how-to-write-drivermethod-in-qsharp-coding-contest
この記事にそった,Solve関数に対するoperationをつくっておけば,コンテスト実施時のデバッグもある程度やりやすそうです.
DumpMachineについて
operation Test() : () {
body {
using (register = Qubit[1]) {
let q = register[0];
DumpMachine("dump-initial.txt");
Solve(q,-1);
DumpMachine("dump.txt");
Reset(q);
}
}
}
\QSharpTestProject1\QSharpApplication1\bin\Debug\netcoreapp2.0
実行時のテストのためにこのDumpMachine関数を使うと,上記のパスに(僕の場合は)dump.txtとdump-initial.txtが作られたので,それを確認して出力を確認しました.
公式ドキュメントでもDumpMachineによるtesting&debuggingについて書かれています.
https://docs.microsoft.com/en-us/quantum/techniques/testing-and-debugging?view=qsharp-preview&tabs=tabid-vs2017
結局,例えば前回のsummer の方のwarmupのB問題を例にとると,以下の様にTestとSolveを書き換えて,テストできるようにしました.
operation Test() : () {
body {
using (qubits = Qubit[2])
{
DumpMachine("dump-initial.txt");
Solve(qubits,2);
DumpMachine("dump.txt");
ResetAll(qubits);
}
}
}
operation Solve (qs : Qubit[], index : Int) : ()
{
body
{
let q0 = qs[0];
let q1 = qs[1];
if(index >= 2) {
X(q1);
}
if(index % 2 == 1) {
X(q0);
}
H(q0);
CNOT(q0, q1);
}
}
これであとはsolveの引数に応じてtestを書き換えながらdump.txtを確認してデバッグする,という環境が整いました.
using Microsoft.Quantum.Simulation.Simulators;
namespace Solution
{
class Driver
{
static void Main(string[] args)
{
using (var sim = new QuantumSimulator())
{
var received = Test.Run(sim).Result;
}
}
}
}
複数のQubitを宣言する場合
using((x,y)=(Qubit(),Qubits[3])){}
のように書けばいける.