Help us understand the problem. What is going on with this article?

Q# の Operation と Function についてのメモ

More than 1 year has passed since last update.

Q# の Operation と Function について、あれどうだっけとググってしまう私のような方向けのメモです。

TL;DR

  • 量子ビットを操作するのが Operations、古典コンピューターで実行可能なのが Functions。
  • Operation と Function は第一級オブジェクトである。
  • Operation と Function は部分適用がサポートされる。

ドキュメント

Q# techniques - operations and functions

概要

Operations

例1
operation BitFlip(target : Qubit) : Unit {
    body (...) {
        X(target);
    }
}
  • Operation の定義は operation キーワードから始まる。
  • 続く BitFlip が Operation の名前
  • <operation name> <input tuple>:<output tuple> で記述される
    • <input tuple><variable name>: <type> で記述される
    • Q# は入力と出力が内部的にはそれぞれ 1 つで、すべて tuple として扱われる。ので、インフォーマルには "tuple-in, tuple-out な言語" といわれる
  • 上記の場合は
    • 入力が Qubit である target
    • 出力はない。Unit は出力がないことを示す。(F# の Unit と同じらしい)
  • body は Operation 内の処理を記述するために必要な宣言
例2
operation Superdense(here : Qubit, there : Qubit) : (Result, Result) {
    body (...) {
        CNOT(there, here);
        H(there);

        let firstBit = M(there);
        let secondBit = M(here);

        return (firstBit, secondBit);
    }
}
  • 上記例の場合、出力は Result 型が二つ含まれる Tuple となる
  • 出力がない場合のみ Variants (Controlled とか Adjoint とか) を定義できる。
例3
operation PrepareEntangledPair(here : Qubit, there : Qubit) : Unit {
    body (...) {
        H(here);
        CNOT(here, there);
    }

    adjoint auto;
    controlled auto;
    controlled adjoint auto;
}
  • 上記の auto は Variants をコンパイラが自動で生成することを意味する。
  • コンパイラが自動生成できない場合や効率的な Variants を手動で生成したい場合は auto を使わないこともできる

Functions

例1
function Square(x : Double) : (Double) {
    return x * x;
}
  • body でくくる必要がないという差異を除けばあとは大体 Operation と一緒
例2
operation U(target : Qubit) : Unit {
    body (...) {
        let angle = RandomReal()
        Rz(angle, target)
    }
}
  • 乱数を取得して、取得した乱数に基づいた回転を行うオペレーションだが、このオペレーションに対してはエルミート行列が定義できない
  • ので、Adjoint は定義できない、コンパイラが処理できない
  • 同様に Controlled も定義できない

Operation と Function は第一級オブジェクトである

第一級オブジェクトについてはこちらを参照のこと

例1
operation FirstClassExample(target : Qubit) : Unit {
    body (...) {
        let ourH = H;
        ourH(target);
    }
}
  • 上記はアダマール変換を行う HourH という変数に代入している
例2
operation ApplyTwice(op : (Qubit => Unit), target : Qubit) : Unit {
    body (...) {
        op(target);
        op(target);
    }
}
  • 上記ではオペレーションの引数として op という別のオペレーション (入力は Qubit、出力なし)と Target を受け取っている
例3
function TeleporationDecoderForMessage(hereBit : Result, thereBit : Result)
        : (Qubit => Unit : Adjoint, Controlled)
{
    if (hereBit == Zero && thereBit == Zero) {
        return I;
    } elif (hereBit == One && thereBit == Zero) {
        return X;
    } elif (hereBit == Zero && thereBit == One) {
        return Z;
    } else {
        return Y;
    }
}
  • 出力に Cotnrolled や Adjoint などの Variant を指定することもできる

Fnction や Operation の部分適用

例1

Function や Operation は部分適用が可能

operation ApplyTwice(op : (Qubit => Unit), target : Qubit) : Unit {
    body (...) {
        op(target);
        op(target);
    }
}

operation PartialApplicationExample(op : (Qubit => Unit), target : Qubit) : Unit {
    body (...) {
        let twiceOp = ApplyTwice(op, _);
        twiceOp(target);
    }
}
  • _ は部分適用のうち、未適用部分を示す
  • 上記例の場合、twiseOp というでは一つ目の引数であるOperation は Op で固定されるが、Target は未指定なので twiseOp 呼び出し時に指定する
例2
function SquareOperation(op : (Qubit => Unit)) : (Qubit => Unit) {
    return ApplyTwice(op, _);
}
  • 上記のように部分適用した Opearation を返すこともできる
tehishik
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away