【OpenMP】MacでLLVMを使ってOpenMPの環境を作った

OpenMPの環境構築に手間取った

数値計算を行う上で必ずいつか必要になる並列計算ライブラリであるOpenMPとMPI. このうち,今回はOpenMPの環境を作ろうとして非常に手間取ったので,そのまとめを行う.

LLVMを使う

参考記事によれば,「LLVM 8.1から公式のclangがOpenMPに対応した」そうです. 2018/11/14現在,”OpenMP Mac” と検索すると2017年頃の記事が大量にヒットするのですが, そのどれもがほとんどclang-ompを導入した記事になっています. しかし,LLVMが公式にOpenMPに対応したことでclang-ompは更新されなくなりました.

導入

homebrewを使うと簡単です.

$ brew install llvm

これでインストールは完了です. そして,次のようにエイリアスを作ることでOpenMPをビルドする時のコマンドを作ってしまいます. 次のテキストを.bash_profile.zshrcに追記してください.自分はbashを昔捨ててzshを使ってますので .zshrcへの記述が必要になりました.

#OpenMP                                                                                                                                                
alias clang-omp='/usr/local/opt/llvm/bin/clang -fopenmp -L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib'
alias clang-omp++='/usr/local/opt/llvm/bin/clang++ -fopenmp -L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib'

以上でもう使えるようになっています.

使い方

サンプルとして次のようなファイルを作って見ましょう.

#include <omp.h>
#include <stdio.h>
int main() {
#pragma omp parallel
printf("Hello from thread %d, nthreads %d\n", omp_get_thread_num(), omp_get_num_threads());
}

そして,次のようなコマンドを使います.

$ clang-omp -fopenmp hello.c -o hello

これで実行ファイルができますので,それを実行した結果が次になります.

$ ./hello
Hello from thread 0, nthreads 8
Hello from thread 6, nthreads 8
Hello from thread 2, nthreads 8
Hello from thread 1, nthreads 8
Hello from thread 7, nthreads 8
Hello from thread 4, nthreads 8
Hello from thread 3, nthreads 8
Hello from thread 5, nthreads 8

実は自分はここでハマってました.恥ずかしい... clangだけで普通のコンパイラが起動してしまうので,そこを勘違いすると,次のようなエラーが出ます.

$ clang -fopenmp hello.c -o hello
ld: library not found for -lomp
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)

リンクがないとか言われてますね...そりゃそうだ()

参考

qiita.com

clang-omp.github.io

【LaTeX】長い数式の折り返し

長い数式を打ちたかった

数値計算の式を打ち込んでいると,どうしても差分形式の式を書かねばならず,そんな時に式が長くなりがちでした. すると必然的に式が長くなって紙からはみ出してしまう.それを解消.

最初にヒットした方法

例えばこの方法 www.irohabook.com

どうやらsplitコマンドなるものを使えば解決することができそうだ.ということで試したのはこちら.

\begin{equation}
\begin{split}
   u^*_{i,j} = &u^n_{i,j} - \Delta t \left\{u^n_{i,j}\frac{u^n_{i+1,j} - u^n_{i-1,j}}{2\Delta x} + v^n_{i,j}\frac{u^n_{i,j+1} - u^n_{i,j-1}}{2\Delta y} + \\
   &\frac{1}{Re}\left(\frac{u^n_{i+1,j} - 2u^n_{i,j} + u^n_{i-1,j}}{(\Delta x)^2} + \frac{u^n_{i,j+1} - 2u^n_{i,j} + u^n_{i,j-1}}{(\Delta y)^2}\right) \right\}
\end{split}
\end{equation}

だがエラーがでた

なにやらエラーが,それがこれ.

Extra }, or forgotten \right. [\end{split}]

考えてみるに,途中で強制改行\\をしているせいで,大きい一つの括弧が二つの数式に分けて考えられ,その結果left\{\right\}の対応が取れなくなってしまったらしい.

解決

でどうしようかと思っていたら英語で検索したらいいパッケージを見つけることができた.

tex.stackexchange.com

これに基づいて再度書きなおしたのがこれ

\documentclass{article}
\usepackage{breqn}
\begin{document}
\begin{dmath}
    v^*_{i,j} = v^n_{i,j} - \Delta t \left\{u^n_{i,j}\frac{v^n_{i+1,j} - v^n_{i-1,j}}{2\Delta x} + v^n_{i,j}\frac{v^n_{i,j+1} - v^n_{i,j-1}}{2\Delta y} + \frac{1}{Re}\left(\frac{v^n_{i+1,j} - 2v^n_{i,j} + v^n_{i-1,j}}{(\Delta x)^2} + \frac{v^n_{i,j+1} - 2v^n_{i,j} + v^n_{i,j-1}}{(\Delta y)^2}\right) \right\}
\end{dmath}
\end{document}

するとこんな感じになる. f:id:kane-please:20181107181616p:plain

うん,まぁいい感じ.

【macOS Mojave】macOS MojaveにアプデしたらCのヘッダーファイルが読み込まれなくなった件

macOSアプデしたら、なぜかCのコードでエラーが大量発生した

表題の通りです.macOSをMojaveにアプデしたら,今まで動いていたCのコードが全く動かなくなりました. 最初は自分が使っているIDE,「CLion」がOSのアプデにより何かおかしくなったのかな?と思ってCLionのアプデをしたりしましたが,全く変わりませんでした.

原因は?

やはり新OSリリース直後なので,諸々の対応が追いついてないのでは?という意見がありました. [MacOS Mojave]pyenvでpythonのインストールがzlibエラーで失敗した時の対応 - Qiita
直接的な原因としては,デフォルト設定でCのヘッダーファイルが/usr/includeに置かれないことにあるようです.
しかし,そんなこと今までなかったぞ...と思っていると本質的な原因がわかりました.
そもそも,macではCやC++コンパイラXCode由来のようで,OSアプデをした後にXCodeもアプデをしたのですが,そのアプデ内容に 「Mojave用のmacOS SDK headerがデフォルトで入っていないのが原因」みたいです.

対処法は?

問題はここからなのですが,様々な記事で指摘されている通り,対処法はそのSDKファイルを手に入れることなのですが,なぜかみなさん既にPCに入っていて

 /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

にあるとのこと.自分も探してみたのですが,

$ cd /Library/Developer/CommandLineTools/Packages/
> cd: no such file or directory:

はい,ない.

ということで,まずAppleデベロッパーアカウントを使って目的のSDKファイルを手に入れます.
まずはこのAppleのサイト( https://developer.apple.com/download/more/ )に入ってください.僕の場合はアカウントはいつの間にか持ってました. ログイン後,以下のような画面になります.そこでCommand Line Tools (macOS 10.14) for Xcode 10.1をダウンロードしてください.

f:id:kane-please:20181107000159p:plain
Apple Developrs

これを入れることにより,先ほどのディレクトリにSDKファイルが生まれます.あとは

$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /

で,基本的にCのコードは全て動くようになります.

CLionの再設定(蛇足)

上の手順に従えば,基本的にCのコードは動くようになるはずです. 自分はIDEでCLionを使っているのですが,エディタ上では赤いままだったので,それを直すために以下のことをしました.

  • Tools | CMake | Reset Cache and Reload Project

キャッシュ決して再読み込みすれば,勝手に直ってくれました.CLion最高!

最後に

macOS MojaveではこのSDKファイルの設定がないせいで,PythonRailsにも被害が及んでいるようです.さらに友人の話だとgitも動かなくなったという話(また入れればいいだけだけど)も聞きましたので,皆様もOSアプデは注意して,しっかりバックアップを取ってから行いましょう!

参考

qiita.com

qiita.com

Rails: macOSをMojaveにアップグレード後`bundle install`がエラーになった場合の対応方法

intellij-support.jetbrains.com

【C++】クラス,構造体は参照渡しで変数名を簡単にした

クラスを使うと変数名が長くなる

長い...

最近はクラスの勉強もかねて,数値計算のコードを半ば無理矢理にクラスを使って書いています. そこで,ちょっと問題になったのが,「クラスを使うと変数名が長くなってしまう事案」です.
例えば以下のようなコードを見てみてください.teacherには1.0を代入して,studentには099まで代入してるだけです.

#include <iostream>
#include <vector>

struct MySchool{
    double teacher;
    std::vector<std::vector<double> > student;
};

int main(){
    MySchool school;

    //これはまあ許してやろう
    school.teacher = 1.0;

    school.student.resize(10);
    for(int i = 0; i<10; i++){
        school.student[i].resize(10);
    }

    for (int i = 0; i< 10; i++){
        for(int j = 0; j< 10; j++){
            //ンンンー!イライラしてくる!!
            school.student[i][j] = 10*i + j;
            std::cout << school.student[i][j] << std::endl;
        }
    }
    return 0;
}

どうですか,流石にこれ,みにくいですよね...

ならばどうする?

いくつかの方法があり,その中でもまぁありかなというのが以下の二つ.

  • ポインタの利用
  • 参照渡し

しかし,ポインタの利用を行うとまたひどく見た目が悪い. 主要なところだけ示すと,こんな感じ

 std::vector<std::vector<double> >* student = &school.student;

    //ちゃんと元のschool.studentが変更されているか確認
    for(int i = 0; i<10; i++){
        for(int j=0; j<10; j++){
            (*student)[i][j] = 10*i + j - 1;
            std::cout << school.student[i][j] << std::endl;
        }
    }

まぁ,悪くないんだけど,やはりなんだか見にくい...

結論

ということで,参照渡しを使うしかないですね. やはりC++なんだから,参照渡し,ガンガン使っていこうよ!というお話です.

#include <iostream>
#include <vector>

struct MySchool{
    double teacher;
    std::vector<std::vector<double> > student;
};

int main(){
    MySchool school;

    //参照渡し
    double& teacher = school.teacher;
    std::vector<std::vector<double> >& student = school.student;

    //色々値とか変更してみる
    teacher = 1.0;

    student.resize(10);
    for(int i = 0; i<10; i++){
        student[i].resize(10);
    }
    for (int i = 0; i< 10; i++){
        for(int j = 0; j< 10; j++){
            student[i][j] = 10*i + j;
        }
    }

    //ちゃんと元のschool.studentが変更されているか確認
    for(int i = 0; i<10; i++){
        for(int j=0; j<10; j++){
            std::cout << school.student[i][j] << std::endl;
        }
    }
    return 0;
}

【C++】vector二重配列の容量確保の仕方

二重配列のVectorの容量の確保の仕方

宣言の時にVevtor配列を初期化すると同時に確保するのはいいんですけど,それをコードの途中で,しかも二重配列ってどうすんだ?と思って軽く調べてので記録します.

結論

要するに,for文でresizeメソッドで確保すればいいらしい.(なんかダサい)

#include <iostream>
#include <vector>

int main()
{
    //ここから
    std::vector<std::vector<int> > v;
    v.resize(10); 
    for(int i = 0; i<10; i++){
        v[i].resize(10);
    }
    //ここまで

    //出力して確認
    for(int i = 0; i<10; i++){
        for(int j = 0; j<10; j++){
            v[i][j] = 10*i + j;
            std::cout << v[i][j] <<std::endl;
        }
    }
}

なお,補足として,上のresizeメソッドにreserveメソッドを入れても動きます. しかし,自分の認識ではreserveはあくまで容量の確保しかしないので,エラーになると思っていたのですが...

この原因はまた今度調べたいと思います.

参考

negi-magnet.hatenablog.com

【NLP】日本語Word2Vecの学習済みモデルの設定

白ヤギさんのWiki全文学習モデル

バイトの関係で日本語のWord2Vecを使い必要が出て来た。
どうやらバイト先では、白ヤギコーポレーションが出している、Wiki全文を学習させたモデルを使うことが慣例になっているらしい。 今回はそのモデルを使ってWord2Vecの類義語の発見を行ってみた。 また、ついでにPyCharmでそのvenvを用いれるように設定した。

ローカルに保存するまでの手順

まずはモデルのダウンロード

基本的にはGithubの指示に従えばいいです。保存したいパスまで移動してgit cloneします。

$ mkdir shiroyagi
$ cd shiroyagi/
$ git clone https://github.com/shiroyagicorp/japanese-word2vec-model-builder.git

終わったら、そのディレクトリに移動して、サブモジュールの初期化を行います。

$ cd japanese-word2vec-model-builder/
$ git submodule init
$ git submodule update

そのあとは仮想環境の設定に入ります。 一応バージョンとかの関係もあるので、ここでは白ヤギ専用に環境を別に作ったほうがいいかなと思いました。

$ python3 -m venv .env

そのあとは、requirements.txtに書かれたモジュールを仮想環境にじゃんじゃか入れていきます。

$ . .env/bin/activate
$ pip3 install -r requirements.txt

ちなみに仮想環境はdeactivateで終了できますよね。

$ deactivate

さて、最後にモデルをダウンロードしますが、これがかなり重い...最悪二時間弱かかります。また、PCもすごい熱くなりますw
またどうやらmecabも自動で入るらしいので、以前mecab入れてたのでなんか変なことにならなければいいんですけど。
例えば、ダウンロード中に以下のように表示されました。

[install-mecab-ipadic-NEologd] : Install completed.
[install-mecab-ipadic-NEologd] : When you use MeCab, you can set '/Users/hattoriatsuki/Documents/Git/source_python/shiroyagicorp/japanese-word2vec-model-builder/output/dic' as a value of '-d' option of MeCab.
[install-mecab-ipadic-NEologd] : Usage of mecab-ipadic-NEologd is here.
Usage:
    $ mecab -d /PATH/shiroyagicorp/japanese-word2vec-model-builder/output/dic ...

これでとりあえずローカルに保存するのは終わり。

PyCharmで使えるようにする

次のような手順を踏めば良い。

  1. preferencesを開く
  2. project Interpreter横の歯車アイコンをクリック
  3. Add local
  4. Existing environmentを選択
  5. Interpreter欄に/path/japanese-word2vec-model-builder/.env/bin/python3を入力
  6. OK

以上のようにすると、japanese-word2vec-model-builder/内のvenvactivateになる

参考

github.com

qiita.com

atc.hateblo.jp

【C++】複数ファイル && Vector入出力

入出力でつまづいた

csvファイルから読み込んだ値をvectorに入れようと思ったら、意外とめんどくさかった。 あとは、以下の点で地味につまづいた。
・複数ファイルに分けたコードの実行が久々だった
Vectorの受け渡しがよく考えたら参照渡しでないといけなかった

main.cpp

#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include "sub.h"


std::vector<std::string> split(std::string& input, char delimiter)
{
    std::istringstream stream(input);
    std::string field;
    std::vector<std::string> result;
    while (getline(stream, field, delimiter)) {
        result.push_back(field);
    }
    return result;
}

int main()
{
    int n = 4;
    std::ifstream ifs("data.csv");
    std::string line;
    std::vector<int> v;

    while (std::getline(ifs, line)) {

        std::vector<std::string> strvec = split(line, ',');

        for (int i=0; i<strvec.size();i++){
            v.push_back(std::stoi(strvec[i]));
        }
    }
    for(auto itr=v.begin(); itr<v.end(); itr++){
        std::cout << *itr << std::endl;
    }
    numnum(v, n);
    for(auto itr=v.begin(); itr<v.end(); itr++){
        std::cout << *itr << std::endl;
    }
}

sub.cpp

#include <vector>
#include <iostream>

void numnum(std::vector<int> &v, int n){
    std::vector<int>* cpv = &v; // アドレスコピー
    for(int i = 0; i < (*cpv).size(); ++i){
        (*cpv)[i] += n;
    }
}

sub.h

#ifndef STUDY_TEST_SUB_H
#define STUDY_TEST_SUB_H

void numnum(std::vector<int> &v, int n);

#endif //STUDY_TEST_SUB_H

参考

qiita.com