Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

簡易ドキュメント #60

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 89 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,108 @@
# qulacs2023

Qulacs2023(正式名称未定)は、量子回路シミュレータ [Qulacs](https://github.com/qulacs/qulacs) をもとに再開発された、新しい Python/C++ ライブラリです。
大規模な量子回路、ノイズを伴う量子回路、パラメトリック量子回路の高速シミュレーションを実行することができます。
本ライブラリは、MITライセンスの下で公開しています。

[Qulacs](https://github.com/qulacs/qulacs) に比べ、以下の点が改善されています。

- [Kokkos](https://github.com/kokkos/kokkos) をベースとした実装により、実行環境(CPU/GPU) の切り替えを容易に行うことができます。切り替えの際にコードを変更する必要はありません。
- 同じ量子回路で、よりよい実行速度を実現します。
- ポインタをユーザから隠蔽したことにより、より安全に、簡単に記述できます。
- [nanobind](https://github.com/wjakob/nanobind) の導入により、よりコンパクトかつ高速な Python へのバインディングを実現します。

## 依存ライブラリ

- GCC 11 以上
- CMake 3.21 以上
- CUDA 12.2 以上(GPU利用時のみ)

## ビルド・実行方法
## C++ ライブラリとしてのインストール

### ビルド (CPU)
```
script/build_gcc.sh
```
Qulacs2023 を静的ライブラリとしてインストールするには、以下の一連のコマンドを実行します。

### ビルド(GPU)
```
QULACS_USE_CUDA script/build_gcc.sh
```txt
git clone https://github.com/Qulacs-Osaka/qulacs2023
cd qulacs2023
./script/build_gcc.sh
```

※キャッシュ変数がセットされるため、ターゲットを変えてビルドする際は `build/CMakeCache.txt` を削除する
NVIDIA GPU と CUDA が利用可能ならば、以下のコマンドで GPU バージョンをインストールできます。ビルドスクリプトの実行の際に `QULACS_USE_CUDA` オプションを付けます。

### テスト
```txt
QULACS_USE_CUDA=ON ./script/build_gcc.sh
```
ninja -C build test

ただし、オプションを変更して再ビルドする際には、CMake にセットされたキャッシュ変数をクリアするため、必ず以下のコマンドを実行してください。

```txt
./script/clean.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean、依存ライブラリの全てを吹き飛ばしてしまって大変なのでrm build/CMakeCache.txtでもいいかもしれない(要検証)

```

### qulacs2023 を用いての C++ 単一ファイルの手元実行
`exe` の中に cpp ファイルを作成し、`exe/CMakeLists.txt` に追記してビルド
## Python へのインストール

### フォーマット
```txt
git clone https://github.com/Qulacs-Osaka/qulacs2023
cd qulacs2023
pip install .
```
ninja -C build format

### サンプルコード(Python)

```Python
from qulacs2023 import *
import math

def main():
n_qubits = 3
state = StateVector.Haar_random_state(n_qubits, 0)

circuit = Circuit(n_qubits)
circuit.add_gate(X(0))
circuit.add_gate(CNOT(0, 1))
circuit.add_gate(Y(1))
circuit.add_gate(RX(1, math.pi / 2))
circuit.update_quantum_state(state)

observable = Operator(n_qubits)
observable.add_random_operator(1, 0)
value = observable.get_expectation_value(state)
print(value)

initialize(InitializationSettings().set_num_threads(8))
main()
finalize()
```

### Python へのインストール
要確認
### サンプルコード(C++)

```cpp
#include <iostream>

#include <circuit/circuit.hpp>
#include <gate/gate_factory.hpp>
#include <operator/operator.hpp>
#include <state/state_vector.hpp>

int main() {
qulacs::initialize(); // must be called before using any qulacs methods
{
const int n_qubits = 3;
qulacs::StateVector state = qulacs::StateVector::Haar_random_state(n_qubits, 0);
std::cout << state << std::endl;

qulacs::Circuit circuit(n_qubits);
circuit.add_gate(qulacs::X(0));
circuit.add_gate(qulacs::CNOT(0, 1));
circuit.add_gate(qulacs::Y(1));
circuit.add_gate(qulacs::RX(1, M_PI / 2));
circuit.update_quantum_state(state);

qulacs::Operator observable(n_qubits);
observable.add_random_operator(1, 0);
auto value = observable.get_expectation_value(state);
std::cout << value << std::endl;
}
qulacs::finalize(); // must be called last
}
```
218 changes: 218 additions & 0 deletions docs/ja/cpp_tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# C++ チュートリアル

## プログラムの開始と終了

Qulacs2023の関数やデータ構造は、すべて`qulacs`名前空間に定義されています。

Qulacs2023を利用する際には、使用するリソースを初期化するために、プログラム開始時に必ず`qulacs::initialize()`を呼び出す必要があります。
これをしない場合エラーとなり、プログラムが終了します。

同様に、プログラムの終了の際にはリソースを解放するため、`qulacs::initialize()`を呼び出す必要があります。
`qulacs::initialize()`を呼び出す際には、すべての`qulacs::StateVector`オブジェクトがデストラクトされていることを要請します。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

// 実行するソースコード

}
qulacs::finalize();
}
```

## 量子状態

### 量子状態の生成

以下のコードで $n$ qubitの量子状態を生成します。
生成した量子状態ははじめ、 $|0\rangle^{\otimes n}$ に初期化されています。
メモリが不足している場合はプログラムが終了します。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

// 5-qubitの状態を生成
// |00000>に初期化されている
const unsigned int n = 5;
qulacs::StateVector state(n);

}
qulacs::finalize();
}
```

### 量子状態の状態ベクトルの取得

量子状態を表す $2^n$ の長さの配列を、`std:vector<qulacs::Complex>`型として取得します。
特にGPUで量子状態を作成したり、大きい $n$ では非常に重い操作になるので注意してください。
配列の要素の型である`qulacs::Complex`型は、ほとんど`std::complex`と同じように扱うことができます。

```cpp
#include <iostream>
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

const unsigned int n = 5;
qulacs::StateVector state(n);

// 配列を取得
auto data = state.amplitudes();

}
qulacs::finalize();
}
```

### 量子状態の初期化

生成した量子状態を初期化するために、いくつかの方法が用意されています。
以下のようにすると、計算基底に初期化したり、ランダムな状態に初期化したりできます。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

const unsigned int n = 5;
qulacs::StateVector state(n);

// |00000>に初期化
state.set_zero_state();
// |00101>に初期化
state.set_computational_basis(0b00101);
// ランダムな初期状態を生成(実行毎にランダム)
state = qulacs::StateVector::Haar_random_state();
// シードを指定してランダムな初期状態を生成
state = qulacs::StateVector::Haar_random_state(0);

}
qulacs::finalize();
}
```
`std::vector<qulacs::Complex>`を介して初期化することや、
インデクスを指定して単一の要素のみを初期化することもできます。
`std::vector`を介する場合、サイズは$2^n$であることが要請されます。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

const unsigned int n = 5;
const unsigned int dim = 1 << 5; // (=2^5=32)
qulacs::StateVector state(n);

// 量子状態のデータを配列から初期化
// すべての状態の確率振幅を等しくする例
std::vector<qulacs::Complex> vec(dim, Complex(1, 0));
state.load(vec);
state.normalize(); // Σ(確率振幅)^2=1 となるよう正規化

// |00000>と|11111>の確率振幅が等しくなるように初期化
state.set_zero_norm_state();
state.set_amplitude_at_index(0b00000, Complex(1, 0));
state.set_amplitude_at_index(0b11111, Complex(1, 0));
state.normalize();

}
qulacs::finalize();
}
```

### 量子状態のコピーとライフタイム

次のようにして量子状態を複製できます。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

const unsigned int n = 5;
qulacs::StateVector state(n);

// コピーして新たな量子状態を作成
auto second_state = state.copy();

}
qulacs::finalize();
}
```

`qulacs::StateVector`の代入操作は、状態ベクトルの保存領域を**シャローコピー**します。
次のように`copy`メソッドを介さず代入操作を行った場合、`state`と`second_state`は内部で同じ状態ベクトルを共有して保持することになるため、期待した実行結果となりません。

```cpp
#include <state/state_vector.hpp>

int main(){
qulacs::initialize();
{

const unsigned int n = 5;
qulacs::StateVector state(n);
state.set_computational_basis(0b00101);

// 新たな量子状態を作成できていない
// stateとsecond_stateは同じ状態ベクトルを共有してしまう
auto second_state = state;

}
qulacs::finalize();
}
```

`qulacs::StateVector`は内部に参照カウンタを持っており、データの管理を`std::shared_ptr`のように行っています。
つまり、ある`qulacs::StateVector`オブジェクトが生成されてから、そのオブジェクトが参照されなくなるまでが、オブジェクトのライフタイムです。

### 量子状態に関する計算

他にもさまざまなメソッドが用意されています。
詳しくはドキュメント(未準備)を参照してください。

```cpp
#include <state/state_vector.hpp>

int main() {
qulacs::initialize();
{

const unsigned int n = 5;
qulacs::StateVector state(n);

// 2乗ノルムの計算
double norm = state.compute_squared_norm();
// Z基底で測定した時のentropyの計算
double entropy = state.get_entropy();

// index-th qubitをZ基底で測定して0を得る確率の計算
unsigned int index = 3;
double zero_prob = state.get_zero_probability(index);

// 周辺確率を計算する
// 以下は0,4-th qubitが0、1,2-th qubitが1と測定される確率の例
// 0,1以外の値は無効値
std::vector<unsigned int> vals{ 0,1,1,2,0 };
double marginal_prob = state.get_marginal_probability(vals);

}
qulacs::finalize();
}
```
Loading