閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

2021年ふりかえり

みたいな日記は書いていなかったのだけど、日記なのだから書いたらいいのでは、とふと思い。

しかし今年はずっとステイホームで、書き残すようなイベントも特になかったのだった。買い物もほとんどしなかったしなぁ…。

去年末から新しい環境での仕事になりましたが、幸いリモート可能で家でぬくぬく仕事しておりました。緊急事態宣言が解除されて、少し出勤イベントも発生しましたが、もう一年経つのに初めて顔を見る人とかいて昔のオフ会かってなったり。

10年ぶりくらいに仕事でC++を使ったり、Python機械学習(CNN)やったり少し持ちネタが増えた一年でした。昔はBoost使ってコンパイルおせぇと言いつつやりくりしていたことが標準ライブラリだけでできたり、ラムダもautoも範囲forも普通に使えて良い時代になったなーと思いました。昔のノリでstd::bindとかも使ったりしていたけど、令和ではこれもラムダで書いちゃう方が速いんですって?

ゲーム

今年は全然できませんでした。ずっと家にいて暇はあったんですけどねぇ。電源入れるのにもエネルギーが必要で。唯一スパロボ30はクリアできました。イカルガ無双で結構難易度低かったですね。

電子書籍はぼちぼち読んでいましたが、ちょうど今日読み終えた「プロジェクト・ヘイル・メアリー」が最高によかったです。あとはマーダーボット・ダイアリーの続編とか。SFはやっぱりいいですね。

最近はラノベもそこそこ読むようになってきましたが、軽く読めるのが良くて来年はもっと割合増えるかも。

着る毛布を買った

こたつに入っていても上半身が冷えるので買ってみたのですがもこもこで着心地も良く、暖かくていい感じです。仕事中も装備していますが、着たまま外に出そうで危ない。

static変数を返す関数で、変数をlambdaで初期化するイディオム

tensorflowのソースにこんな実装があって、なるほどと思いました。

bool RequireCudnnDeterminism() {
  static bool require_cudnn_determinism = [] {
    // TODO(reedwm): Remove the TF_CUDNN_DETERMINISTIC env var.
    bool cudnn_deterministic = false;
    TF_CHECK_OK(tensorflow::ReadBoolFromEnvVar("TF_CUDNN_DETERMINISTIC",
                                               /*default_val=*/false,
                                               &cudnn_deterministic));
    return cudnn_deterministic;
  }();
  return tensorflow::OpDeterminismRequired() || require_cudnn_determinism;
}

この手の関数で、初回だけどこかから値を取り出して設定しておくみたいなのはよくやりますが(そうか?)、その処理のためにstatic変数を非constにしなきゃいけないのは嫌だなと思っていたんですよね。上記コードだとconstじゃないんですが、

int get_nantoka()
{
    static int const nantoka = [] {
        return 321;
    }();
    return nantoka;
}

実際にはこうも書けるので、かなり気持ちいいです。

has_parent_pathの戻り値

www.little-cuckoo.jp

path::has_parent_path - cpprefjp C++日本語リファレンス

パスにルートパスのみが含まれていれば、ルートパスの親はルートパスと見なされてtrueが返る

ということでした。

c++ - How can a std::filesystem root path have itself as a parent? - Stack Overflow

has_relative_pathはパスにルートパスのみが含まれていれば、falseが返るので、

fs::path path(R"(/Users/Public/Documents)");
while (path.has_relative_path())
{
    std::cout << path.stem() << std::endl;
    path = path.parent_path();
}

なら良さそう。何か書く前にリファレンスを読みましょう。

ルートディレクトリでhas_parentがfalseになると思っていた

#include <filesystem>

namespace fs = std::filesystem;

int main()
{
    fs::path path(R"(C:\Users\Public\Documents)");
    while (path.has_parent_path())
    {
        std::cout << path.stem() << std::endl;
        path = path.parent_path();
    }

    return 0;
}

みたいなコードを書くと無限ループになるんですね。なんか、ルートディレクトリはさらに上にはいけないからhas_parentはfalseになると思っちゃったんですよね。

fs::path path(R"(C:\Users\Public\Documents)");
while (path != path.root_path())
{
    std::cout << path.stem() << std::endl;
    path = path.parent_path();
}

みたいにするのかな。

Pythonのpathlibも同じでした。

from pathlib import Path
print(Path(r"C:\\").parent) # => C:\

朝、意味も無くドトールにコーヒーを飲みに行ったりしている

朝起きて、わざわざ駅前のドトールまで行ってコーヒー飲んでまた家に帰ってきて始業する、みたいなことをやっています。

目覚ましと、僅かながら歩数稼ぎと、ついでに抜きがちな朝食を食べておいて痩せないようにしたい、という辺りが目的。

通勤……というか通勤電車に乗るのは嫌だけど、まったく体を動かさないのもなぁということで。特にやっててよかったとか体感できるところはありませんが、退店時に「いってらっしゃいませ」と言ってもらいながら、帰るんですけどね~と思いつつ帰路につくのはちょっと楽しいです。

体のためというならついでにラジオ体操とかやる方がよっぽど良さそうではありますが…やるか?

OpenCVのMat構造体で任意の列を処理したいとき

メモリ構造を考えるとそれはそう、という話なんですが、こういうコードを書くと実行時間に差が出ます。

cv::TickMeter ticks;
ticks.start();

for (int i = 0; i < 1000; ++i)
{
    const auto m = cv::mean(mat.row(i))[0];
}

ticks.stop();
std::cout << ticks << std::endl;

ticks.reset();
ticks.start();

for (int i = 0; i < 1000; ++i)
{
    const auto m = cv::mean(mat.col(i))[0]; // ここの処理はなんでもいい (この例だとreduceで良くなっちゃうけど)
}

ticks.stop();
std::cout << ticks << std::endl;
0.0058812sec // mat.row
0.343708sec  // mat.col

ずっと一次元のデータと戯れてきたため二次元とか行列は知見がなくて、こういう時どうするのが良いんでしょう。transposeしちゃう?

cv::transpose(mat, mat);
for (int i = 0; i < 1000; ++i)
{
    const auto m = cv::mean(mat.row(i))[0];
}