はじめてのあいてんさー

[^1]: ここで言うtensorとはただの多次元配列を指します.
[^2]: "簡単"という概念は主観的なものですので, 例えば「terminal? 黒い画面のやつのことなんか知らん!」と言われると泣いてしまいます.
[^3]: どちらかと言うと実際は抽象度の高い実装による汎用性柔軟性の高さに特徴があるような気がしますが, 
[^4]: 後述の`options.mk`内に明記されています.
[itensor]:http://itensor.org/
[^5]: ちなみに無限系のiDMRGも同じ`itensor/sample`にあり, `make`した際に全てcompileされますので`./idmrg`で実行できます.

#はじめに
[ITensor][itensor]はtensorを使って[^1]数値計算を行うためのclassや[密度行列くりこみ群法](http://tensornetwork.org/mps/algorithms/dmrg/)(DMRG)などのalgorithmを実行する函数などを提供するC++ libraryです.

一言で言うと**超簡単に[^2]DMRGの計算ができます**[^3].

[開発者](http://itensor.org/about.html)がMac愛好家なのかmacOSでのcompileが恐ろしく簡単だったので紹介したいと思います.
ITensorのinstallから有限系のDMRGを実行するところまで行きたいと思います.

ITensorについてもっと詳しく知りたい方は[公式][itensor]が一番詳しいと思いますのでそちらを御覧ください.

[こちら](https://qiita.com/cometscome_phys/items/88e8dff3e3dc90298132)でも簡単に紹介されています.

#実行環境
macOS Mojave 10.14.3

#ITensorのinstall
まずITensor libraryのcompileを行います.

行うことは

- ITensorのcompileに必要なもののinstall
- ITensorのGitHub repositoryのclone
- ITensor libraryのMakefileの設定 (任意)→make

です. 

以下で順に説明していきます.

かなり冗長に書いていると思うのでやかましいと思う方は[公式](http://www.itensor.org/docs.cgi?page=install&vers=cppv3)をご覧いただくか, 必要な処理を次の節にまとめたのでそれをささっと実行してください.

##ITensorのcompileに必要なもののinstall
- C++ compiler
- Git
- Make
- Xcode (BLAS/LAPACK用)

この中でinstallしていないものがあればinstallを行なってください.
install方法は簡単にですが, [こちら](https://qiita.com/ultimatile/items/092acef84825e5f7f0b1)にまとめています.

なお, 2019年12月現在のITensorの最新versionは3.1.1です. 
ITensor3はC++17対応のC++ compiler (Clang v5~) が必要です. 
ITensor3は今年releaseされたばかりなので, bugが怖い方はITensor2をcompileしてください. 
ITensor2はC++11対応のC++ compiler (Clang v3~) が必要です. 
Intel compilerはC++11の機能が完全には提供されていないため非推奨とされています[^4].

##ITensorのGitHub repositoryのclone
ITensorを置きたいdirectoryで以下を実行してください.

``` bash:terminal
git clone https://github.com/ITensor/ITensor itensor
cd itensor
``` 

ITensor2をご所望の方は更に

``` bash:itensor/
git checkout v2
```

を実行してください.

##ITensor libraryのMakefileの設定 (任意)→make
ここではCommand Line Tools for Xcodeに含まれているC++ compiler Clang++とXcodeに含まれるBLAS/LAPACK ([Accelerate  Framework](https://developer.apple.com/documentation/accelerate)) を用いてcompileすることを想定しています.

`options.mk.sample`にITensorをcompileするための設定が書いてありますので`options.mk`にcopyします:

``` bash:itensor/
cp options.mk.sample options.mk
```

次にeditorなどで`options.mk`を編集しますが, `option.mk`のdefault設定はGNU C++ compiler (g++) なのですが, Command Line Tools for Xcodeを入れている場合, `g++`は`clang++`へのaliasになっています. したがって編集しない場合compileにはclang++が使われます.

`options.mk`にはIntel MKLなどの他のBLAS/LAPACKを用いるためのoptionも記載されていますので, ご自身の環境に合わせて適宜変更してください.

編集が終わったら

``` bash:itensor/
make
```

を実行してください.

#ITensorのinstallまとめ
ITensorのversion毎にITensorをinstallするまでのcommandをまとめました. `options.mk`を編集してないのでdefault設定でのcompileになります.
##ITensor3
``` bash:install_itensor3.sh
git clone https://github.com/ITensor/ITensor itensor
cd itensor
cp options.mk.sample options.mk
make
```

##ITensor2
``` bash:install_itensor2.sh
git clone https://github.com/ITensor/ITensor itensor
cd itensor
git checkout v2
cp options.mk.sample options.mk
make
```

#DMRGの実行(動作確認)
動作確認として`itensor/sample`にある有限系のDMRG `dmrg.cc`を実行します[^5]. makeの設定までしてありますので, sample directoryに移動してmake commandを実行するだけです.

```bash:itensor/
cd sample
make
```

compileが終わったら実行してみましょう.

```bash:itensor/sample/
./dmrg
```

以下のような感じの出力が出たらcompileできています.
これであなたもあいてんさー!

```
Initial energy = -99.00000
Sweeps:
1  Maxm=10, Minm=1, Cutoff=1.0E-10, Niter=2, Noise=1.0E-07
2  Maxm=20, Minm=1, Cutoff=1.0E-10, Niter=2, Noise=1.0E-08
3  Maxm=100, Minm=1, Cutoff=1.0E-10, Niter=2, Noise=0.0E+00
4  Maxm=100, Minm=1, Cutoff=1.0E-10, Niter=2, Noise=0.0E+00
5  Maxm=200, Minm=1, Cutoff=1.0E-10, Niter=2, Noise=0.0E+00


    vN Entropy at center bond b=50 = 0.581075353146
    Eigs at center bond b=50: 0.7840 0.2045 0.0058 0.0024 0.0020 0.0012 
    Largest m during sweep 1/5 was 10
    Largest truncation error: 4.71751e-05
    Energy after sweep 1/5 is -138.241288573618
    Sweep 1/5 CPU time = 0.0838s (Wall time = 0.0816s)

    vN Entropy at center bond b=50 = 0.812720219293
    Eigs at center bond b=50: 0.5910 0.3827 0.0078 0.0061 0.0061 0.0058 
    Largest m during sweep 2/5 was 20
    Largest truncation error: 3.83855e-06
    Energy after sweep 2/5 is -138.899105014327
    Sweep 2/5 CPU time = 0.296s (Wall time = 0.276s)

    vN Entropy at center bond b=50 = 0.850686099160
    Eigs at center bond b=50: 0.5090 0.4612 0.0075 0.0073 0.0071 0.0071 
    Largest m during sweep 3/5 was 81
    Largest truncation error: 9.98892e-11
    Energy after sweep 3/5 is -138.938252544024
    Sweep 3/5 CPU time = 1.898s (Wall time = 1.590s)

    vN Entropy at center bond b=50 = 0.854386693666
    Eigs at center bond b=50: 0.4919 0.4777 0.0075 0.0074 0.0073 0.0073 
    Largest m during sweep 4/5 was 97
    Largest truncation error: 9.99146e-11
    Energy after sweep 4/5 is -138.939940458503
    Sweep 4/5 CPU time = 4.324s (Wall time = 3.244s)

    vN Entropy at center bond b=50 = 0.855234844932
    Eigs at center bond b=50: 0.4864 0.4830 0.0074 0.0074 0.0074 0.0074 
    Largest m during sweep 5/5 was 102
    Largest truncation error: 9.99549e-11
    Energy after sweep 5/5 is -138.940079532642
    Sweep 5/5 CPU time = 6.199s (Wall time = 4.361s)

Ground State Energy = -138.9400795326

Using overlap = -138.9400795326
```

##おまけ:`dmrg.cc`の中身
ちなみに`dmrg.cc`中身は以下のようになっています(わざわざここに張る必要もないのですが...). やることは計算したいHamilotonian `H`, 初期状態 `psi`, 計算条件 `sweeps`を用意して`dmrg`に渡す(そのあと出力された`psi`で物理量を計算する)というのが基本的な使い方になります.
(2020/3/10追記: version 2かversion 3かで書き方が微妙に異なるのを失念していましたので両versionのものを張り直しました.)

###ITensor3

```C++:itensor/sample/dmrg.cc
#include "itensor/all.h" 
using namespace itensor; 

int
main() 
     { 
     int N = 100; 

     // 
     // Initialize the site degrees of freedom 
     // Setting "ConserveQNs=",true makes the indices 
     // carry Sz quantum numbers and will lead to  
     // block-sparse MPO and MPS tensors 
     // 
     //auto sites = SpinHalf(N); //make a chain of N spin 1/2's 
     auto sites = SpinOne(N); //make a chain of N spin 1's 

     // 
     // Use the AutoMPO feature to create the  
     // next-neighbor Heisenberg model 
     // 
     auto ampo = AutoMPO(sites); 
     for(auto j : range1(N-1)) 
         { 
         ampo += 0.5,"S+",j,"S-",j+1; 
         ampo += 0.5,"S-",j,"S+",j+1; 
         ampo +=     "Sz",j,"Sz",j+1; 
         } 
     auto H = toMPO(ampo); 

     // Set the initial wavefunction matrix product state 
     // to be a Neel state. 
     // 
     auto state = InitState(sites); 
     for(auto i : range1(N)) 
         { 
         if(i%2 == 1) state.set(i,"Up"); 
         else         state.set(i,"Dn"); 
         } 
     auto psi0 = MPS(state); 

     // 
     // inner calculates matrix elements of MPO's with respect to MPS's 
     // inner(psi,H,psi) = <psi|H|psi> 
     // 
     printfln("Initial energy = %.5f", inner(psi0,H,psi0) ); 

     // 
     // Set the parameters controlling the accuracy of the DMRG 
     // calculation for each DMRG sweep.  
     // Here less than 5 cutoff values are provided, for example, 
     // so all remaining sweeps will use the last one given (= 1E-10). 
     // 
     auto sweeps = Sweeps(5); 
     sweeps.maxdim() = 10,20,100,100,200; 
     sweeps.cutoff() = 1E-10; 
     sweeps.niter() = 2; 
     sweeps.noise() = 1E-7,1E-8,0.0; 
     println(sweeps); 

     // 
     // Begin the DMRG calculation 
     // 
     auto [energy,psi] = dmrg(H,psi0,sweeps,"Quiet"); 

     // 
     // Print the final energy reported by DMRG 
     // 
     printfln("\nGround State Energy = %.10f",energy); 
     printfln("\nUsing inner = %.10f", inner(psi,H,psi) ); 

     return 0; 
     } 
```

###ITensor2

```C++:itensor/sample/dmrg.cc
#include "itensor/all.h"

using namespace itensor;

int 
main()
    {
    int N = 100;

    //
    // Initialize the site degrees of freedom.
    //
    //auto sites = SpinHalf(N); //make a chain of N spin 1/2's
    auto sites = SpinOne(N); //make a chain of N spin 1's

    //
    // Use the AutoMPO feature to create the 
    // next-neighbor Heisenberg model
    //
    auto ampo = AutoMPO(sites);
    for(int j = 1; j < N; ++j)
        {
        ampo += 0.5,"S+",j,"S-",j+1;
        ampo += 0.5,"S-",j,"S+",j+1;
        ampo +=     "Sz",j,"Sz",j+1;
        }
    auto H = MPO(ampo);

    // Set the initial wavefunction matrix product state
    // to be a Neel state.
    //
    auto state = InitState(sites);
    for(int i = 1; i <= N; ++i) 
        {
        if(i%2 == 1)
            state.set(i,"Up");
        else
            state.set(i,"Dn");
        }
    auto psi = MPS(state);

    //
    // overlap calculates matrix elements of MPO's with respect to MPS's
    // overlap(psi,H,psi) = <psi|H|psi>
    //
    printfln("Initial energy = %.5f", overlap(psi,H,psi) );

    //
    // Set the parameters controlling the accuracy of the DMRG
    // calculation for each DMRG sweep. 
    // Here less than 5 cutoff values are provided, for example,
    // so all remaining sweeps will use the last one given (= 1E-10).
    //
    auto sweeps = Sweeps(5);
    sweeps.maxm() = 10,20,100,100,200;
    sweeps.cutoff() = 1E-10;
    sweeps.niter() = 2;
    sweeps.noise() = 1E-7,1E-8,0.0;
    println(sweeps);

    //
    // Begin the DMRG calculation
    //
    auto energy = dmrg(psi,H,sweeps,"Quiet");

    //
    // Print the final energy reported by DMRG
    //
    printfln("\nGround State Energy = %.10f",energy);
    printfln("\nUsing overlap = %.10f", overlap(psi,H,psi) );

    return 0;
    }

```
<!--
DMRGの実行fileの作成
以上まででとりあえずITensorが動くようになりました. しかしDMRGを`itensor/sample`の`dmrg.cc`のまま使おうとするとHamilotonianや実行parameterを変える度にcompileが必要で面倒です. そこでHamiltonianや計算条件のparameterを実行時input fileとして与えるやり方が一般的だと思います.

また今のままだとmakeの設定も分からないままなので自分の作ったをどうmakeすればいいのかわかりません.
-->