【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)
リンクがないとか言われてますね...そりゃそうだ()
参考
【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\}
の対応が取れなくなってしまったらしい.
解決
でどうしようかと思っていたら英語で検索したらいいパッケージを見つけることができた.
これに基づいて再度書きなおしたのがこれ
\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}
するとこんな感じになる.
うん,まぁいい感じ.
【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
をダウンロードしてください.
これを入れることにより,先ほどのディレクトリに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ファイルの設定がないせいで,PythonやRailsにも被害が及んでいるようです.さらに友人の話だとgitも動かなくなったという話(また入れればいいだけだけど)も聞きましたので,皆様もOSアプデは注意して,しっかりバックアップを取ってから行いましょう!
参考
【C++】クラス,構造体は参照渡しで変数名を簡単にした
クラスを使うと変数名が長くなる
長い...
最近はクラスの勉強もかねて,数値計算のコードを半ば無理矢理にクラスを使って書いています.
そこで,ちょっと問題になったのが,「クラスを使うと変数名が長くなってしまう事案」です.
例えば以下のようなコードを見てみてください.teacher
には1.0
を代入して,student
には0
〜99
まで代入してるだけです.
#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
はあくまで容量の確保しかしないので,エラーになると思っていたのですが...
この原因はまた今度調べたいと思います.
参考
【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で使えるようにする
次のような手順を踏めば良い。
- preferencesを開く
- project Interpreter横の歯車アイコンをクリック
- Add local
- Existing environmentを選択
- Interpreter欄に
/path/japanese-word2vec-model-builder/.env/bin/python3
を入力 - OK
以上のようにすると、japanese-word2vec-model-builder/
内のvenv
がactivate
になる
参考
【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