忍者ブログ
  • 2019.07
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 2019.09
XORとは
えっ、そこ?みたいな観点でつづっていきたいと思わなくもないこともない
nwpfhがお送りするブログです。
PR
【2030/12/31 23:59 】 | 未選択
                                    
javascriptのflatMapとpythonの内包表記
javaでflatMapを覚えてから奇妙だなと思っていた。
これって何に使うのだろうかと。

結論から言うと直積を求めたいときに使うのである。

もし、組み合わせを求めたい場合、どのように求めるだろうか。

■pythonソース
teams = range(5)
[(x, y) for xi, x in enumerate(teams) for yi, y in enumerate(teams) if xi < yi]
■python結果
[(0, 1),
 (0, 2),
 (0, 3),
 (0, 4),
 (1, 2),
 (1, 3),
 (1, 4),
 (2, 3),
 (2, 4),
 (3, 4)]

実はこれと同じことをflatMapでも行える。
■javascriptソース
range = (x)=>function*(){ for(var i = 0;i<x;i++) {yield i;}};
teams = range(5);
Array.from([[]])
.flatMap(x=>Array.from(teams()).map(y=>x.concat(y)))
.flatMap((x, xi)=>Array.from(teams()).filter((y,yi)=>xi<yi).map(y=>x.concat(y)))
■javascript結果
(10) [Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2)]
0: (2) [0, 1]
1: (2) [0, 2]
2: (2) [0, 3]
3: (2) [0, 4]
4: (2) [1, 2]
5: (2) [1, 3]
6: (2) [1, 4]
7: (2) [2, 3]
8: (2) [2, 4]
9: (2) [3, 4]
length: 10
__proto__: Array(0)
おもしろいなあ。
【2019/06/16 18:19 】 | Python | 有り難いご意見(0)
                                    
C++のboostでgraphviz+dotを使ってみた
グラフを作りたかったので、graphvixを使ってみました。

【参考】Boost.Graph Graphviz形式で重みを出力

#include <fstream>
#include <vector>
#include <string>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
struct EdgeWithInfo
{
    int nodeS;
    int nodeE;
    int weight;
    std::string name;
};

typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
                              boost::no_property, boost::property<boost::edge_all_t, EdgeWithInfo>>
    Graph;
typedef std::pair<int, int> Edge;

enum
{
    A,
    B,
    C,
    D,
    E,
    N
};

const std::string name[] = {"A", "B", "C", "D", "E"};

int main()
{
    const std::vector<EdgeWithInfo> edgeWithInfo =
        {
            {A, B, 3, "→B"},
            {A, C, 1, "→C"},
            {A, D, 4, "→D"},
            {B, E, 2, "→E"},
            {C, E, 5, "→E"},
            {D, E, 6, "→E"}};

    std::vector<Edge> edges;

    std::transform(edgeWithInfo.begin(), edgeWithInfo.end(), std::back_inserter(edges),
                   [](auto ei) {
                       return std::make_pair(ei.nodeS, ei.nodeE);
                   });

    const Graph g(edges.begin(), edges.end(), edgeWithInfo.begin(), N);

    std::ofstream file("test.dot");
    boost::write_graphviz(file,
                          g,
                          boost::make_label_writer(name),
                          [](auto &graph_) {
                              return [&graph_](std::ostream &out, auto edge) {
                                  const EdgeWithInfo &ewi =
                                      *reinterpret_cast<const EdgeWithInfo *>(&boost::get(boost::edge_all, graph_, edge));
                                  out << "[";
                                  out << "weight=" << ewi.weight << ",";
                                  out << "label=" << ewi.name;
                                  out << "]";
                              };
                          }(g));
}

digraph G {
0[label=A];
1[label=B];
2[label=C];
3[label=D];
4[label=E];
0->1 [weight=3,label=→B];
0->2 [weight=1,label=→C];
0->3 [weight=4,label=→D];
1->4 [weight=2,label=→E];
2->4 [weight=5,label=→E];
3->4 [weight=6,label=→E];
}
正攻法ではない気がするけど、まあ良しとしよう。
【2019/05/04 09:22 】 | C/C++ | 有り難いご意見(30)
                                    
超万能なsorted
Pythonでの不満。Python2にあったsorted関数のcmpがなくなって、keyになった。
なぜ、cmpはなくなったのだろうか?考えてみた。

まず、sortedへの不満として、複数キーの昇順・降順ができなくなった。というものがあった。
誤りである。
どうやらkeyにタプルを返すと勝手に複数キーの昇順としてソートしてくれるようだ。
つまり、文字は反転。数字はマイナスにすることで、それらしきものができる。
c=[('a', 1), ('a', 2), ('b', 2), ('b', 1)]
sorted(c, key=lambda x: (tuple(map(lambda z:(0xff-z), x[0].encode("cp932"))), -x[1]))
[('b', 2), ('b', 1), ('a', 2), ('a', 1)]
ここで気づいた。この比較用キーの作成はcmpの場合、ソート方法に依存してしまう。O(2*NlogN)の頻度で比較用キーが作成されてしまうのだ。
この点、key指定だと比較用キーはO(N)のみの作成となる。
すばらしい

ただし、文字列の降順としては可変長の場合、前述の方法は使えない。なので、classを作ってみた。
class Keys:
    def __init__(self, v, isAscs):
        self.v = v
        self.isAscs = tuple(isAscs)

    def __lt__(self, other):
        for i, s, isAsc, o in zip(range(len(self.isAscs)-1, -1, -1), self.v, self.isAscs, other.v):
            lt = [lambda p1, p2: p1 > p2, lambda p1, p2: p1 < p2][isAsc]
            ret = lt(s, o)
            if ret or i and lt(o, s):
                break
        return ret

    @staticmethod
    def of(isAscs, keymap=lambda x:x):
        return lambda item: Keys(keymap(item), isAscs)


if __name__ == "__main__":
    arr = [("a", 2), ("b", 1), ("a", 1), ("b", 2)]
    print(arr)
    #1項目め降順、2項目め昇順
    print(sorted(arr, key=Keys.of((False, True))))
    #1項目め2文字目昇順、1項目め1文字目昇順
    print(sorted(arr, key=Keys.of((True, False), keymap=lambda x:(x[0][1], x[0][0]))))
うん、素晴らしい。
【2019/05/02 08:43 】 | Python | 有り難いご意見(0)
                                    
C++17でモンテカルロを並列化してみた。(GNU Version)
C++17でモンテカルロを並列化してみた。に触発されて、GNU版で作ってみました
■コンパイル
$ g++ test.cc -Wall -march=native -std=c++17 -O3  -fopenmp
■ソース
#include <parallel/algorithm>
//#include <execution>
#include <atomic>
#include <mutex>
#include <iostream>
#include <random>
#include <array>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    static int const NUM = 1000000000;
    static int threads = 8;
    static_assert(std::atomic<int>::is_always_lock_free);
    if (argc >= 2)
    {
        threads = atoi(argv[1]);
    }
    auto nums = std::vector<int>(threads);
    for (auto &num : nums)
    {
        num = NUM / threads;
    }
    __gnu_parallel::_Settings s;
    s.algorithm_strategy = __gnu_parallel::force_parallel;
    __gnu_parallel::_Settings::set(s);

    std::atomic counter = {0};

    __gnu_parallel::for_each(nums.begin(), nums.end(), [&counter](int num) {
        std::random_device rnd;
        thread_local std::mt19937 mt(rand());
         std::uniform_real_distribution<double> score(0.0, 1.0);
        for (auto &&no = 0; no < num; ++no)
        {
            auto &&x = score(mt);
            auto &&y = score(mt);
            if ((x * x + y * y) < 1.0)
            {
                counter++;
            }
        }
    });

    std::cout << "PI = " << 4.0 * counter / NUM << std::endl;
}
■結果
$ time ./a.out 1
PI = 3.14155

real	0m27.461s
user	0m27.469s
sys	0m0.001s
$ time ./a.out 2
PI = 3.14159

real	0m29.238s
user	0m58.008s
sys	0m0.016s
$ time ./a.out 3
PI = 3.14151

real	0m28.447s
user	1m24.458s
sys	0m0.000s
$ time ./a.out 4
PI = 3.14155

real	0m32.101s
user	2m5.238s
sys	0m0.020s

なぜか延べ時間(user)が増えるだけでreal時間が減りません。。。
そこでソースを修正してみました。
■ソース修正後
#include <parallel/algorithm>
//#include <execution>
#include <atomic>
#include <mutex>
#include <iostream>
#include <random>
#include <array>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    static int const NUM = 1000000000;
    static int threads = 8;
    static_assert(std::atomic<int>::is_always_lock_free);
    if (argc >= 2)
    {
        threads = atoi(argv[1]);
    }
    auto nums = std::vector<int>(threads);
    for (auto &num : nums)
    {
        num = NUM / threads;
    }
    __gnu_parallel::_Settings s;
    s.algorithm_strategy = __gnu_parallel::force_parallel;
    __gnu_parallel::_Settings::set(s);

    std::atomic counter = {0};

    __gnu_parallel::for_each(nums.begin(), nums.end(), [&counter](int num) {
        std::random_device rnd;
        thread_local std::mt19937 mt(rand());
        int _counter = 0;
        std::uniform_real_distribution<double> score(0.0, 1.0);
        for (auto &&no = 0; no < num; ++no)
        {
            auto &&x = score(mt);
            auto &&y = score(mt);
            if ((x * x + y * y) < 1.0)
            {
                _counter++;
            }
        }
        counter += _counter;
    });

    std::cout << "PI = " << 4.0 * counter / NUM << std::endl;
}

■結果
$ time ./a.out 1
PI = 3.14155

real	0m20.263s
user	0m20.255s
sys	0m0.000s
$ time ./a.out 2
PI = 3.14159

real	0m10.117s
user	0m20.223s
sys	0m0.000s
$ time ./a.out 3
PI = 3.14151

real	0m7.409s
user	0m22.209s
sys	0m0.000s
$ time ./a.out 4
PI = 3.14155

real	0m6.129s
user	0m24.492s
sys	0m0.001s
core4個分で20秒から6秒にその後、8個に増やしても増えませんでした。。。
なかなかのパフォーマンスなり。
【2019/05/01 17:11 】 | 未選択 | 有り難いご意見(1)
                                    
| ホーム | 次ページ>>