【C++】WSL上でEigenとmatplotlib-cppを使って数値計算を快適にする話

IT関連

C++で行列演算とグラフを簡単に扱いたいんだけど

こんにちは、novです。

今回はC++で数値計算をする際に便利なライブラリ

  • Eigen (線形代数ライブラリ)
  • matplotlib-cpp (Pythonの描画ライブラリmatplotlibをC++で使えるようにするライブラリ)

をWSL上で使うためにネットの海を彷徨った経緯を記録しようと思います。WSLを使っているのは以下の記事の環境を使用しているからです。

これらのライブラリを使用するにあたり、特に後者については日本語の情報がそこまで多くなく、まともに動かすまでかなり時間がかかりました。

ハマっている人の助けになれるかもしれません。

前置きを長くしても仕方ないので、早速本題に入っていきましょう!

検証環境

  • OS: Windows10 / WSL – Ubuntu 18.04LTS

Eigenの設定

Eigenはヘッダオンリーの線形代数ライブラリであり、インクルードパスを通すだけで簡単に使用することができます。

ここでは

  • WSLでのEigenのインストール方法
  • VSCodeのtasks.jsonに設定する内容
  • の二つに言及します。

    WSLにおけるEigenのインストール方法と、インストールされるディレクトリ

    以下のQiita記事の一つ目の方法でできます。

    Eigenのインストール方法(WSL) - Qiita
    はじめにWSLでのC++の外部ライブラリの管理について - Qiitaインストール先の話など細かいところは割愛しているので,わからない場合はこちらの記事を先に読んでください.方法①aptでイ…

    具体的には、WSLのコンソール上で

    sudo apt install libeigen3-dev

    を実行すればOKです。インストール先は/usr/include/で、eigen3という名前で入っています。

    VSCodeのtasks.jsonに設定する内容

    先ほどインストールしたeigen3へのインクルードパスを通せばOKです。具体的には、実行するg++のコマンドの引数にI-オプションで上記のパスを渡すようにします。

    そんなわけで、以前作成した WSL + VSCodeの環境においては、以下の設定をするだけで動かすことができます。

    {
        "tasks": [
            {
                "type": "cppbuild",
                "label": "C/C++: g++ アクティブなファイルのビルド",
                "command": "/usr/bin/g++",
                "args": [
                    "-g",
                    "${file}",
                    "-I",
                    "/usr/include/eigen3", // ここを追加
                    "-o",
                    "${fileDirname}/${fileBasenameNoExtension}"
                ],
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "problemMatcher": [
                    "$gcc"
                ],
                "group": {
                    "kind": "build",
                    "isDefault": true
                },
                "detail": "デバッガーによって生成されたタスク。"
            }
        ],
        "version": "2.0.0"
    }

    上記コード内にコメントで追記している部分 -I /usr/include/eigen3 を追加すればOKということです。

    matplotlib-cppの設定

    次はmatplotlib-cppの設定です。これは、C++のコードからPythonのmaplotlibを呼び出し、グラフの描画ができるライブラリです。
    一部の機能を除き、使用することができます。

    これもEigenと同じくヘッダオンリーのライブラリなので、ヘッダの配置とインクルードパスの設定で動作させることができます。

    ただし、Eigenと異なりPythonと連携をするための環境構築・設定が必要となるため作業量は少し多いです。

    作業の概要は以下のようになります。

  • WSL上でpython-dev、numpy、matplotlibのインストール
  • tasks.jsonに各種設定を行う
  • 画像を表示するのではなく、保存する場合にはmatplotlibのバックエンドが”Agg”になるよう設定を行う
  • 以下、それぞれについて細かく見ていきます。

    なお、今回の設定では、”matplotlibcpp.h”は、作業するフォルダに配置するものとします。

    WSL上でPython関係のソフトをインストール

    Eigenと同じく、aptを利用してインストールしていきます。

    sudo apt install python3-dev
    sudo apt install python3-m
    sudo apt install python3-numpyatplotlib

    matplotlib-cppでは、python2系を推奨しているという話もありますが、現状Python3系(上記の方法だとPython3.6がインストールされる)で問題なく動作しています。
    python2系でやりたい場合は

    sudo apt install python2.7-dev
    sudo apt install python-matplotlib
    sudo apt install python-numpy

    のようにしてください(なお、自分の環境ではPython2系ではコンパイルがうまくできませんでした)。

    以上の作業を行った後、/usr/include以下に、

    • python3.6
    • python3.6m

    というフォルダが存在することを確認します。

    次に行うtasks.jsonの設定で、ここへのパスを通していきます。

    tasks.jsonの設定

    以下のように設定します。

    {
        "tasks": [
            {
                "type": "cppbuild",
                "label": "C/C++: g++ アクティブなファイルのビルド",
                "command": "/usr/bin/g++",
                "args": [
                    "-g",
                    "${file}",
                    "-I",
                    "/usr/include/eigen3",
                    "-I", // 追加
                    "/usr/include/python3.6", // 追加
                    "-lpython3.6m", // 追加
                    "-std=c++11", // 追加
                    "-o",
                    "${fileDirname}/${fileBasenameNoExtension}"
                ],
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "problemMatcher": [
                    "$gcc"
                ],
                "group": {
                    "kind": "build",
                    "isDefault": true
                },
                "detail": "デバッガーによって生成されたタスク。"
            }
        ],
        "version": "2.0.0"
    }

    「追加」とコメントを書いている部分が今回追加した内容になります。

    特に重要なのは以下の箇所です。

    {
        // 省略
        "args":[
        // 省略
        "-I", // 追加
        "/usr/include/python3.6", // 追加
        "-lpython3.6m", // 追加
        // 省略
        ]
    }

    -I /usr/include/python3.6 は “Python.h”へのパスをインクルードしており、-lpython3.6mは python3.6 のライブラリへのリンクオプションになります。

    ここまでやれば、ひとまずmatplotlibcpp.hを使用したソースコードのコンパイルが可能になるはずです。

    最後に、matplotlibcppのsaveメソッドを使用する際に必要となる設定を行います。

    matplotlibのバックエンド変更

    上記の設定のまま、saveメソッドを使おうとすると、ビルドしたファイルを実行してもエラーとなってグラフを画像に保存できないはずです。

    解決策としては以下のコマンドを実行し、matplotlibのバックエンドに”Agg”を使用するよう設定します(環境変数の設定)。

    export MPLBACKEND=Agg

    ただし、これを直接コマンドを実行するだけでは今回限りの設定となり、再度シェルを起動するとこの設定が消えています。

    永続化するには、ホームディレクトリにある”.bashrc”を編集し、シェルの起動時に上記のコマンドを実行するよう設定する必要があります。

    WSLはCUIしかないので、vimなどを使用してコマンドラインから”.bashrc”を編集し、上記のコマンドを最後に付け加えてあげましょう。

    参考:フォルダ構成

    githubのリポジトリに例として今回の構成を適用したファイル・フォルダを用意しました。

    Build software better, together
    GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.

    基本的にAtsushi Sakaiさんの下記リポジトリ、matplotlib-cppのexampleフォルダから拝借したファイルを編集したものになっています。

    GitHub - lava/matplotlib-cpp: Extremely simple yet powerful header-only C++ plotting library built on the popular matplotlib
    Extremely simple yet powerful header-only C++ plotting library built on the popular matplotlib - lava/matplotlib-cpp
    GitHub - AtsushiSakai/matplotlib-cpp-starter: This is a starter kit with matplotlib-cpp
    This is a starter kit with matplotlib-cpp. Contribute to AtsushiSakai/matplotlib-cpp-starter development by creating an account on GitHub.

    ご参考までにどうぞ。

    参考サイト

    https://readthedocs.org/projects/matplotlib-cpp/downloads/pdf/latest/

    まとめ

    今回は、以前作成した「WSL + VSCode」のC++環境にEigenとmatplotlib-cppを導入する方法についての話でした。

    両方とも比較的日本語の情報が少なく、ハマるとなかなかツラいものがあります。

    ひとまず、WSLを使用した環境については、ひとまずこれで動かすことができるはずです。

    試してみたいと考えている人の助けになれば幸いです。それでは!

    コメント

    タイトルとURLをコピーしました