Q#の入門をするが

Q#言語の入門を行うのですが、
量子レベルの勉強をいきなりエセエンジニアにはハードルが高いので
Q#言語のビルド・実行方法などや文法レベルの勉強をしようと思います。

また、各リテラルについてのコピー更新などの
操作関連は別に作ろうかなと思います。

## 参考ページ

- [コピーと更新の式](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/copyandupdateexpressions)
- [型宣言](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/programstructure/typedeclarations)
- [変数宣言と再割り当て](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/statements/variabledeclarationsandreassignments)
- [優先順位と結合性](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/precedenceandassociativity#operators)
- [項目アクセス](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/itemaccessexpressions#item-access-for-user-defined-types)

## 環境構築

今回はDockerイメージ上からQ#言語の練習を行いたいと思います。

### ディレクトリ構成
```bash
/q-sharp-train                       
┣ docker/               # 環境イメージディレクトリ
┃   ┗ Dockerfile        # qサービスのイメージファイル
┣ src/                  # Q#言語のプロジェクトが格納される場所
┃   ┗ ...               
┣ .editorconfig         # 省略
┣ .gitignore            # 省略
┣ docker-compose.yml    # 
┗ README.md             # 省略

```

### Dockerfile
Q#のdocker imageのtagリストは[こちら](https://mcr.microsoft.com/v2/quantum/iqsharp-base/tags/list)
lambdaを使用したい場合は、0.23以降のイメージタグを使用するといいでしょう。

```Dockerfile
FROM mcr.microsoft.com/quantum/iqsharp-base:0.24.206416-beta

WORKDIR /app
```


### docker-compose.yml

```yml
version: '3'
services:
  q:
    build:
      context: .
      dockerfile: ./docker/Dockerfile
    image: qsharp-train:v1
    tty: true
    volumes:
      - ./src:/app
```


上記の環境が構築出来たら以下のいつものコマンドを
コマンドラインから実行しましょう
```powershell
PS C:\q-sharp-train> docker-compose up -d
PS C:\q-sharp-train> docker-compose exec q /bin/bash
...:/app$ 
```


## プロジェクトの構築・実行方法
dotnetからQ#用のtemplateを用いてプロジェクト作成しビルドや実行なども行います。

```bash
# templateからプロジェクトを作成
...:/app$ dotnet new <Template Name or Short Name> -lang Q# -o <project name>

# プロジェクトを実行 カレントディレクトリがプロジェクトディレクトリの場合project指定不要
...:/app$ dotnet run --project <project name>

# Q#のtemplate一覧
...:/app$  dotnet new -i Microsoft.Quantum.ProjectTemplates -n console
...
Template Name                  Short Name     Language  Tags
-----------------------------  -------------  --------  --------------
Class library                  classlib       Q#        Common/Library
Console Application            console        Q#        Common/Console
Quantum Application Honeywell  azq-honeywell  Q#        Common/Console
Quantum Application IonQ       azq-ionq       Q#        Common/Console
xUnit Test Project             xunit          Q#        Test/xUnit

```

今回は```Console Application```のプロジェクトで練習しようと思います。

```bash
# templateからsampleプロジェクトを作成
...:/app$ dotnet new console -lang Q# -o sample
```
実行すると```/src```配下にsampleディレクトリが以下のように作成されると思います。
```bash
/q-sharp-train                     
┣ docker/       
┣ src/                  
┃   ┗ sample/
┃       ┣ Program.qs
┃       ┗ sample.csproj
```
とりあえず、この状態で実行してみましょう。

```bash
...:/app$ dotnet run --project sample
Hello quantum world!
```

## Q#プログラムの実装

現状の```Program.qs```は以下のようになっていると思います。

```c#
// namespace名はproject名と一緒になります。
namespace sample {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    
    @EntryPoint()
    operation HelloQ() : Unit {
        Message("Hello quantum world!");
    }
}
```

流れとしては、```EntryPoint()```と宣言されているHelloQ()から呼び出せる関数を
このnamespaceに追加して呼び出しながら行いたいと思います。

ちなみに、```operation```もしくは```function```であれば```EntryPoint```を指定でき実行できます。

```c#
    @EntryPoint()
    function <任意の関数名>(<任意の実行引数>) : Unit {
        Message("Hello quantum world!");
    }
```


### リテラル

以下のリテラルについて一気に例を記載しますが、```Double```は作るの忘れたので省略します。

| リテラル名 | 概要 | デフォルト値  |
| --- | --- | --- |
| Int |  2, 8, 10, 16進数の表現が可能です。先頭に``0b``, ``0o``, ``0x``が可能で、それ以外10進数になります。| ``0`` |
| BigInt |  Intリテラルに追加で``L``を後置して定義します。例）10進数の場合：``32L``| ``0L`` |
| Double | 小数点の定義を行う為のリテラルです。 | ``0.0`` |
| Bool | ``true``もしくは``false``のみの定義リテラルです。 | ``false`` |
| String | 文字列に関する定義リテラルです。 | ``""`` |
| Range | このリテラルは``start..step..stop``の式で構成されます。``start``, ``step``, ``end``は全てIntリテラルで定義されます。<br>例) <br>1..3 == 1,2,3<br> 2..2..5 == 2,4;| empty range |
| Array | このリテラルは、``[1,2,3]``のようにカンマ区切りで``[``と``]``で囲んだリテラルが配列として定義されます。特別な配列の初期化ルーチンはMicrosoft.Quantum.Arrays名前空間で見つけることができます。| empty array |
| Tuple | Tupleリテラルは1つ以上の任意のリテラルをカンマ区切りで``(``と``)`` で囲み定義します。| all items are set to default values |
| User Defined Types | ユーザー定義型の定義リテラルです。コンストラクタを呼び出しインスタンス化したものをユーザー定義型と定義。 | all items are set to default values |

```Int```と```BigInt```の宣言は以下のようになります。

```c#

    function IntFunc(): Unit{
        let b = 0b11110000;
        let o = 0o52;
        let d = 5;
        let h = 0xFF;
        Message($"IntFunc():{b}:{o}:{d}:{h}:{5+5}");
        /// IntFunc():240:42:5:255:10
    }

    function BigIntFunc(): Unit {
        let bb = 0b1101010L;
        let bo = 0o32L;
        let bd = 3L;
        let bh = 0xFFFFL;
        Message($"BigIntFunc():{bb}:{bo}:{bd}:{bh}:{15L+5L}");
        /// BigIntFunc():106:26:3:65535:20
    }
```
```String```と```Bool```のリテラルは以下のようになります。
```c#
    function StringFunc(): Unit {
        let a = "aaa";
        let b = "bbb";
        let c = a + b;
        Message($"StringFunc():--{a}--{b}--{c}--");
        /// StringFunc():--aaa--bbb--aaabbb--
    }

    function BoolFunc(): Unit {
        let b = true;
        let f = false;
        Message($"BoolFunc():{b}/{f}");
        /// BoolFunc():True/False
    }
```
```Array```、```Range```、```Tuple```のリテラルについては以下のようになります。


```c#
    function ArrayFunc(): Unit{
        let a = [1, 2, 3];
        let b = [2.1, 3.1];
        let c = [a, [4, 5, 6]];
        let d = [5.5, size=3];
        // let d = [a, c]; error
        Message($"ArrayFunc():{a}/{b}/{["aiueo", "aiueo"]} {c} {d}");
       /// ArrayFunc():[1,2,3]/[2.1,3.1]/[aiueo,aiueo] [[1,2,3],[4,5,6]] [5.5,5.5,5.5]

    }

    function RangeFunc(): Unit {
        let a = 1..3;
        let b = 1..2..10;
        let c = 2..2..5;
        Message($"RangeFunc():{a}/{b}/{c}");
        /// RangeFunc():1..1..3/1..2..10/2..2..5
    }

    function TupleFunc(): Unit {
        let a = (1, 0.5, "f");
        let b = ("fabo","tama", 33);

        let v1 = 2;
        let v2 = 0.3;
        let v3 = "c";
        
        let c = (v3, (v2, v1));

        Message($"TupleFunc(): {a} / {b} / {c} / {c}");
        /// TupleFunc(): (1, 0.5, f) / (fabo, tama, 33) / (c, (0.3, 2)) / (c, (0.3, 2))

    }
```

ユーザー定義型について以下のように定義し扱うみたいです。
下の例は、項目名が付いた例になります。[詳細](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/itemaccessexpressions)

```c#
    newtype NamedType = (Integer: Int, Data: Double[]);

    function UserTypeFunc(): Unit {
        mutable original = NamedType(10, [5.0, size=3]);
        Message($"UserTypeFunc(): {original}");
        /// UserTypeFunc(): NamedType((10, [5,5,5]))
        
        // 更新式
        set original w/= Integer <- 8;
        set original w/= Data <- [4.0, size=2];
        mutable a = original::Data;
        set a w/= 0 <- 5.0;
        // 項目名のアクセスには::で指定します。
        Message($"UserTypeFunc(): {original} {original::Data}");
        /// UserTypeFunc(): NamedType((8, [4,4])) [4,4]
    }

```

Q#の```Array```や```User Defined Types```の更新の式は以下のようになります。([詳細](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/copyandupdateexpressions))
上記の例では、下の省略形で更新式を記載しています。
```
// 更新式
set original = original w/ itemAccess <- modification
// 更新式-省略形
set original w/= itemAccess <- modification
```

項目名なしは以下のように扱います。
項目名が存在しないので、```アンラップ演算子```を使用して値を取得します。[詳細](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/itemaccessexpressions#item-access-for-user-defined-types)

```c#
    newtype NonNamedType = (Double, (Int, Int, String), Int);
    ...
    function UserType2Func(): Unit {
        mutable original = NonNamedType(1.1, (5, 5, "STRING"), 5);
        let (head, _, tail) = original!;
        Message($"UserType2Func(): {head}");
        /// UserType2Func(): 1.1
    }
```


## 連結
```Array```、```String```リテラルには、[連結](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/expressions/concatenation)という機能があります。

```c#
    function LinkFunc(): Unit {
        Message("1 msg" + " 2 msg");
        /// 1 msg 2 msg

        let d = [8,9,10] + [1,2,3];
        Message($"{d}");
        /// [8,9,10,1,2,3]
    }
```


## 所感
もうめんどくさいくなったので、後で更新し。。。