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

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

### TL;DR

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

### ドキュメント

[Q# techniques - operations and functions](https://docs.microsoft.com/en-us/quantum/techniques/operations-and-functions?view=qsharp-preview)

### 概要

#### Operations

##### 例1

```cs
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


```cs
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


```cs
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


```cs
function Square(x : Double) : (Double) {
    return x * x;
}
```

- `body` でくくる必要がないという差異を除けばあとは大体 Operation と一緒

##### 例2

```cs
operation U(target : Qubit) : Unit {
    body (...) {
        let angle = RandomReal()
        Rz(angle, target)
    }
}
```

- 乱数を取得して、取得した乱数に基づいた回転を行うオペレーションだが、このオペレーションに対してはエルミート行列が定義できない
- ので、Adjoint は定義できない、コンパイラが処理できない
- 同様に Controlled も定義できない


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

[第一級オブジェクトについてはこちらを参照のこと](https://ja.wikipedia.org/wiki/%E7%AC%AC%E4%B8%80%E7%B4%9A%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88)

##### 例1

```CS
operation FirstClassExample(target : Qubit) : Unit {
    body (...) {
        let ourH = H;
        ourH(target);
    }
}
```

- 上記はアダマール変換を行う `H` を `ourH` という変数に代入している

##### 例2


```cs

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

- 上記ではオペレーションの引数として `op` という別のオペレーション （入力は Qubit、出力なし）と Target を受け取っている

##### 例3


```cs

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 は部分適用が可能

```cs
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


```cs
function SquareOperation(op : (Qubit => Unit)) : (Qubit => Unit) {
    return ApplyTwice(op, _);
}
```

- 上記のように部分適用した Opearation を返すこともできる