トップページへ戻る
過去の日記へ


予定


1月31日(日)

 NOP


1月30日(土)

 NOP


1月29日(金)

 この曰記はあとで自分が読み返すために書いており、かつなるべく時事問題を扱わない、扱っても時事問題そのものに言及しない、というポリシーで書いている。そんなわけで、のちの自分のために背景を書いておくと、とある人が論文を書いて、それを大学からプレスリリースして、炎上してプレスリリースがすぐ消えた、という事例なんだけれども。

 まず、僕も炎上した身として、「防げなかったのか?」というのはあまり意味のある問いじゃないと思う。多くはどこかの防壁で防がれているわけで、「防げなかったもの」だけ見えるから。それに、こういうのをがっちりと防ぐ仕組みは、多分メリットよりデメリットの方が大きい。

 で、こういう炎上を防ぐ「防壁」には様々なものがあるけれど、「論文掲載→プレスリリース」の間には防壁は無いに等しい。なぜかプレスリリースが「大きな成果」としてカウントされる現状では、大学はプレスリリースしたいわけだし、その内容をチェックできるのは基本的に著者だけなんだし、広報は「どのように広報するか」のプロであっても「その内容は正しいか」のチェックはできない。 そんなわけで、「最後の防壁」は査読者だと思うわけ。

 以前にも書いたんだけど、査読者は最後の防壁。本当は研究室セミナーとか、共著者のチェックとか、学会発表とかが「防壁」になるんだけど、僕や今回のケースのように単著だとそういうチェックが効きづらい。 僕はプレプリントサーバにしか出さなかったけど、今回のケースのように論文が通る→プレスリリース、というケースでは、査読者が最後の防壁。そういう意味で、繰り返しになるけれど、査読者がまずい論文を落とすのは、科学の質を保つためというよりは、著者を守るためだと思っている。

 博士課程の時にすごく丁寧な査読レポートを受け取って感激して以来、査読は丁寧にするよう心がけてたけど、炎上後はそれに加えて「まずい論文をちゃんと落とす」ことを心がけている(査読は通すより落とす方が大変)。インパクトファクターが高い論文誌は特に気をつけている。ただ、ちゃんとした査読レポートをもらっても、まずい論文をそのままなんども送ってきたり、別の場所に投稿して通しちゃったりする著者もいるけれど、そこまで面倒は見きれない。

 で、「あまりすごくないことをさもすごいことのように広報する」ことの功罪については、ケースバイケースとしか言いようがない。通す論文全部プレスリリースしちゃう研究者もいるし。僕の「泡バブル」も、論文の手堅さに比べて反響の大きさは明らかにアンバランスだった。しかし、それで「京」を使ってこんなことをやっている人がいる、大規模分子動力学計算の宣伝になる、といった「メリット(?)」を考えると、一概にダメだったとは言えない気もしていて・・・。

 むしろ昨今のアウトリーチ偏重主義がこのまま進むと、全論文プレスリリースとまではいかないまでも、論文通すたびに一般の人が見てすごさがわかる説明文が義務付けられる、くらいにはなるかもしれない。

 裁量労働従事者報告カード提出した。


1月28日(木)

 NOP

 Macで、ターミナル上からmiでファイルを開けるように、

mi='open  -a /Applications/mi2.1/mi.app/Contents/MacOS/mi'

 というエイリアスをかけている。しかし、直接 mi filename.txtとしても、新規作成はできないので、一度touchしてからmiで開いている。

 で、今日、hogehoge.txtをtouchしてからmiで開くと、普通に開けるのだが全く文字が書き込めない。 他のファイルは書き込めるのに、そのファイルだけ書き込めない。ふとウィンドウを見ると「書き込み不可」とあるので、 「あれ?何かロックが残っちゃったかな」と思ってログアウト+ログイン。でも書き込めない。 おかしいと思って端末からもう一度ファイルをチェックすると、なぜかhogehoge.txtというディレクトリができていた。 なぜかtouchのつもりでmkdirを打ち込んだらしい。なんでだ?そんな間違いこれまで一度もしたことないぞ?

 だけど、そもそもなんでmiはディレクトリが開けて、かつ何もできないんだ?と思って、miの「ファイルメニュー」からディレクトリを「開く」してみたら、そのディレクトリの下に移って、ディレクトリそのものは開けない。つまりMacの open -aでディレクトリが渡される動作は想定外、ということか・・・。どうしようかな。

 別にバグでもないし不具合ってほどでもないけど、一応バグ報告してみた。こういう使い方をするユーザもいると、と伝える意味で。


1月27日(水)

 スパコンの通信関係を調べようとして、 Intel® MPI Benchmarksを使ったんだけど、データサイズの中間領域で妙に早い。で、調べたらHA8000 クラスタシステムで MPI 性能を測定する場合の注意点 (PDF)に、Intel MPI Benchmarksはキャッシュの影響を受けるから気をつけろ的なことが書いてあった。あー、同じバッファを繰り返し使うから、ノード内通信の場合にはキャッシュに乗っちゃって、しかもSHMEMで通信するからすごく早く見えちゃうのか・・・。あと、プロセス配置がどうなってるかわからないので、ノード内通信とノード間通信をごっちゃに測ってる気がする。物性研システムBなら、「同一CPU内」「同一ノードのCPU間」「異なるノード間」の三種類はやらないといけない。っつーか自分で組んだ方が早いなこれ。

 どうでもいいけど、なんでPingPong二回測定してんだろ、バグ?条件違う?とずーっとソースを追いかけてて、最後に二回目が「PingPong」ではなく「PingPing」だったことに気がついた・・・。


1月26日(火)

 呼出規約の確認。こんなコードをコンパイルしてみる。

int func(int, int, int, int, int, int, int, int, int );

int func2(void){
  return func(1,2,3,4,5,6,7,8,9);
}

 Linuxではこうなる。

        subq      $40, %rsp                                     #3.16
        .cfi_def_cfa_offset 48
        movl      $1, %edi                                      #4.10
        movl      $2, %esi                                      #4.10
        movl      $3, %edx                                      #4.10
        movl      $4, %ecx                                      #4.10
        movl      $5, %r8d                                      #4.10
        movl      $6, %r9d                                      #4.10
        movl      $7, (%rsp)                                    #4.10
        movl      $8, 8(%rsp)                                   #4.10
        movl      $9, 16(%rsp)                                  #4.10
..___tag_value__Z5func2v.4:
#       func(int, int, int, int, int, int, int, int, int)
        call      func(int, int, int, int, int, int, int, int, int)  

intだと、順番にedi、esi、edx、ecx、r8d、r9dまで使って、それ以降はスタックか。g++でも同じだけど、レジスタに代入する命令の順序が逆なのが謎。

Macでclang++だとこう。

        subq    $48, %rsp
        movl    $1, %edi
        movl    $2, %esi
        movl    $3, %edx
        movl    $4, %ecx
        movl    $5, %r8d
        movl    $6, %r9d
        movl    $7, %eax
        movl    $8, %r10d
        movl    $9, %r11d
        movl    $7, (%rsp)
        movl    $8, 8(%rsp)
        movl    $9, 16(%rsp)
        movl    %r11d, -4(%rbp)         ## 4-byte Spill
        movl    %r10d, -8(%rbp)         ## 4-byte Spill
        movl    %eax, -12(%rbp)         ## 4-byte Spill
        callq   func(int, int, int, int, int, int, int, int, int)

 なんだ?なんでspillしてんだ?-O1以上をつけたらspillが消えた。g++だと-O0でもspillは発生しない。謎。

 SPARCだとこんなん。

/*      4 */    mov     7,%g4
/*      4 */    stx     %g4,[%sp+2223]
/*      4 */    mov     8,%g4
/*      4 */    stx     %g4,[%sp+2231]
/*      4 */    mov     9,%g4
/*      4 */    stx     %g4,[%sp+2239]
/*      4 */    mov     1,%g4
/*      4 */    mov     2,%g5
/*      4 */    mov     3,%o0
/*      4 */    mov     4,%o1
/*      4 */    mov     5,%o2
/*      4 */    mov     6,%o3
/*    ??? */    stx     %o0,[%fp+2039]
/*      4 */    mov     %g4,%o0
/*    ??? */    stx     %o1,[%fp+2031]
/*      4 */    mov     %g5,%o1
/*    ??? */    ldx     [%fp+2039],%l0
/*    ??? */    stx     %o2,[%fp+2023]
/*      4 */    mov     %l0,%o2
/*    ??? */    ldx     [%fp+2031],%l0
/*    ??? */    stx     %o3,[%fp+2015]
/*      4 */    mov     %l0,%o3
/*    ??? */    ldx     [%fp+2023],%l0
/*      4 */    mov     %l0,%o4
/*    ??? */    ldx     [%fp+2015],%l0
/*      4 */    mov     %l0,%o5
/*      4 */    call    func(int, int, int, int, int, int, int, int, int)

 なんかレジスタの値保存しようとしてるように見えるなぁ。-O3つけたらそういうのは消える。

/*      4 */    mov     7,%g1
/*      4 */    mov     8,%g2
/*      4 */    stx     %g1,[%sp+2223]
/*      4 */    mov     9,%g3
/*      4 */    mov     1,%o0
/*      4 */    mov     2,%o1
/*      4 */    mov     3,%o2
/*      4 */    mov     4,%o3
/*      4 */    mov     5,%o4
/*      4 */    mov     6,%o5
/*      4 */    stx     %g2,[%sp+2231]
/*      4 */    call    func(int, int, int, int, int, int, int, int, int)
/*      4 */    stx     %g3,[%sp+2239]

 うわ、g3のstxとcallが逆だ。こういうのなんて呼ぶか忘れたけど、stxが先に実行されるんだよな。 後はx86の場合と同じで、6個までレジスタで、7個以上はスタック経由か。レジスタ一杯あるのに、と思うけど、たくさん引数がある関数呼び出しのコストを下げても、全体の最適化にはあまり効かないだろうし、いいのかな。

 最近x86のアセンブリを見てるのは、これまでちゃんと見たことがなかったから。僕が最初に自分のコードのアセンブリ見たのはDEC Alphaだった気がする。その後、IBM POWER6やSPARC64のアセンブリを見た(Itaniumのもちらっとは見たけど真面目にチューニングはしてない)。要するに全部RISC。 そういう入り方をした人間にとって、x86のレジスタの名前はややこしい。SPARCなら引数の値をo0からo6までに入れるところを、 x86だと順番にedi、esi、edx、ecx、r8d、r9dとかになる。

 doubleも見ておくか。さっきのintをdoubleにすると、x86では8個まではレジスタ(xmm0-7)、9個目からはスタック。 SPARCだと16個までレジスタ(f0〜f30)で、それ以降はスタックか。

 僕がこれまでx86のアセンブリ見てなかったのは、僕のコードがRISC系の石で(同世代のXeonに比べて)遅かったから。そんなわけで「なんでだろう?」と思ってそっちの石のアセンブリを見始めたのが始まりだった気がする。逆にRISC系の石に比べてx86は早かったので、それで満足しちゃってあまり真面目にチューニングしなかったというかこれ以上x86での実行速度が上がっちゃったらRISC系の石の立場が無いというか。 あ、でもAlphaは早かった気がする。特に21264の方。遅かったのはPOWERとSPARC。PA-RISCも遅い印象があったけど、使ったのが登場からだいぶたってたから(7年?)、同世代の石と比べるのは可哀想。

 もう記憶が曖昧だが、Alphaは21164から21264になった時にはっきりと速度の向上を感じた気がするなぁ。単にクロックが上がったせいなのか、OoOが効いたのかはわからない。

 なんか偶然見つけた「Z80 vs 6502」。 2014年にもなって、Z80と6502の命令の最適化合戦をやってて笑う。っていうかマニア多すぎて笑う。次のコメントの「1バイトお得ですね」とか。

【名無し】 LD A,C ; 4 (5) AND #1 ; 7 (8) は BIT 0,C ; 8(9) にした方が4クロックと1バイトお得ですね。

 6502といえばファミコンに6502が採用された経緯を思い出す。これに限らず、当時のこういった業界裏話にはリコーが良く顔を出す。Intel 4004、8080の開発を担当した嶋正利氏も、8080開発時にはリコーだったそうな。その後ザイログを起業してZ80の開発をすることに。

 エクセルで作ったデータをワードで編集とかしてるんだけど、文字化けしたりレイアウト変わったり、そもそも保存がものすごく重かったりするので、とりあえずテキストでだーっと書いて、後でいっきに貼り付ける作戦に。そもそもエクセルでデータを作るのもとてもとても大変。ちょっと凝ったことしようとするとどうにもならないし、メニューもさっぱりわからない。複数のグラフをまとめて修正しようとしてもできない。多分一つ作ったグラフのスタイルを保存し、他のグラフに適用する方法があるんだろうけど、やりかたがさっぱりわからない。

 こういうのどうすればいいんだろ?LaTeXのグラフ連携システムを作ればいいのか?


1月25日(月)

 物理学会の予稿提出した。

 インテルコンパイラのipo(interprocedural optimization)にあたる奴、gccではLTO (link time optimization)と言うらしい。例えばこんなコード。

#include <stdio.h>
int func(void);
int
main(void){
  printf("%d\n",func());
}
int func(void){
  return 1;
}

 これをコンパイルして逆汗。

$ icpc -O3 test.cc test2.cc;objdump -d ./a.out |c++filt|less 
(snip)
  400b9b:       0f ae 1c 24             stmxcsr (%rsp)
  400b9f:       81 0c 24 40 80 00 00    orl    $0x8040,(%rsp)
  400ba6:       0f ae 14 24             ldmxcsr (%rsp)
  400baa:       e8 21 00 00 00          callq  400bd0 <func()>
  400baf:       bf 44 1d 40 00          mov    $0x401d44,%edi
  400bb4:       89 c6                   mov    %eax,%esi
  400bb6:       33 c0                   xor    %eax,%eax
  400bb8:       e8 73 fd ff ff          callq  400930 <printf@plt>

ーO3だけではfuncが呼ばれるが、-ipoをつけるとインライン展開できる。gccなら-fltoをつけると同じことができる。

$ icpc -O3 test.cc test2.cc;objdump -d ./a.out |c++filt|less
(snip)
  400b9b:       0f ae 1c 24             stmxcsr (%rsp)
  400b9f:       bf 24 1d 40 00          mov    $0x401d24,%edi
  400ba4:       be 01 00 00 00          mov    $0x1,%esi
  400ba9:       81 0c 24 40 80 00 00    orl    $0x8040,(%rsp)
  400bb0:       33 c0                   xor    %eax,%eax
  400bb2:       0f ae 14 24             ldmxcsr (%rsp)
  400bb6:       e8 75 fd ff ff          callq  400930 <printf@plt>

1月24日(日)

 NOP


1月23日(土)

 NOP


1月22日(金)

 昨日のPimplイディオム、主眼はアクセス制限ではなく、privateセクションの修正が関係ないところの再コンパイルに波及するのを防ぐのが主目的とのこと。

 で、気になるのはパフォーマンス。もちろんこういうコードを書いている以上、ある程度のパフォーマンス劣化はやむを得ないと割り切っているだろうし、通常、implを介することのオーバーヘッドなんて微々たるものであろう。それを承知の上で、Pimplイディオムが最適化にどれくらい効いてくるか調べてみたくなった。特にIPO関連。

 とりあえずPimpl無し版。

  private:
    int i,j;
  public:
    IntPair(int, int);
    IntPair operator+(const IntPair &y);
    int getI(void) const {return i;};
    int getJ(void) const {return j;};
};
#include "intpair.h"

IntPair::IntPair(int i_, int j_) : i(i_), j(j_) {
}

IntPair
IntPair::operator+(const IntPair &y){
  const int yi = y.getI();
  const int yj = y.getJ();
  return IntPair(i+yi,j+yj);
}

 単に整数の組の和をサポートするクラス。これを以下のtest.ccから呼ぶ。

#include <stdio.h>
#include "intpair.h"
int
main(void){
  IntPair ip1(1,2);
  IntPair ip2(3,4);
  IntPair ip3 = ip1 + ip2;
  printf("%d %d\n",ip3.getI(),ip3.getJ());
}

 これをIntelコンパイラでコンパイルすると、test.ccをコンパイルする時点ではIntPair::operator+の実装が見えないので、最適化できない。しかし、-ipoをつけてコンパイルして、printfを呼ぶところを見てみると

  400b9f:       bf 24 1d 40 00          mov    $0x401d24,%edi
  400ba4:       be 04 00 00 00          mov    $0x4,%esi
  400ba9:       81 0c 24 40 80 00 00    orl    $0x8040,(%rsp)
  400bb0:       ba 06 00 00 00          mov    $0x6,%edx
  400bb5:       33 c0                   xor    %eax,%eax
  400bb7:       0f ae 14 24             ldmxcsr (%rsp)
  400bbb:       e8 70 fd ff ff          callq  400930 <printf@plt>

 と、ちゃんと即値を返せる。ここまでは想定の範囲内。

 さて、これをPimplイディオムを使って、privateメンバであるint i,jを隠蔽しよう。コードはこうなるかな。

#include <memory>
class IntPair{
  private:
    class Impl;
    std::unique_ptr<Impl> impl;
  public:
    IntPair(int i_, int j_);
    ~IntPair(void);
    IntPair operator+(const IntPair &y);
    int getI(void) const ;
    int getJ(void) const ;
};
#include "intpair.h"
class IntPair::Impl{
  private:
    int i,j;
  public:
    Impl(int i_, int j_) : i(i_), j(j_) {};
    int getI(void){return i;};
    int getJ(void){return j;};
};

IntPair::IntPair(int i, int j) : impl(new Impl(i,j)){
}

IntPair::~IntPair(void){
}
int
IntPair::getI(void) const {
  return impl->getI();
}

int
IntPair::getJ(void) const {
  return impl->getJ();
}

IntPair
IntPair::operator+(const IntPair &y){
  int i = impl->getI();
  int j = impl->getJ();
  int yi = y.getI();
  int yj = y.getJ();
  return IntPair(i+yi,j+yj);
}

 コピーコンストラクタとかいろいろ省いてる。これを同じtest.ccから呼ぶ。 コンパイルしてobjdumpしてみる。

$ icpc -std=c++11 -O3 -ipo test.cc intpair.cc
$ objdump -d ./a.out |c++filt 
(snip)
  400cdd:       0f ae 1c 24             stmxcsr (%rsp)
  400ce1:       bf 08 00 00 00          mov    $0x8,%edi
  400ce6:       81 0c 24 40 80 00 00    orl    $0x8040,(%rsp)
  400ced:       0f ae 14 24             ldmxcsr (%rsp)
  400cf1:       e8 3a fe ff ff          callq  400b30 <operator new(unsigned long)@plt>
  400cf6:       bf 08 00 00 00          mov    $0x8,%edi
  400cfb:       c7 00 01 00 00 00       movl   $0x1,(%rax)
  400d01:       c7 40 04 02 00 00 00    movl   $0x2,0x4(%rax)
  400d08:       48 89 44 24 08          mov    %rax,0x8(%rsp)
  400d0d:       e8 1e fe ff ff          callq  400b30 <operator new(unsigned long)@plt>
  400d12:       c7 00 03 00 00 00       movl   $0x3,(%rax)
  400d18:       bf 08 00 00 00          mov    $0x8,%edi
  400d1d:       c7 40 04 04 00 00 00    movl   $0x4,0x4(%rax)
  400d24:       48 89 44 24 10          mov    %rax,0x10(%rsp)
  400d29:       48 8b 44 24 08          mov    0x8(%rsp),%rax
  400d2e:       8b 18                   mov    (%rax),%ebx
  400d30:       44 8b 70 04             mov    0x4(%rax),%r14d
  400d34:       e8 f7 fd ff ff          callq  400b30 <operator new(unsigned long)@plt>
  400d39:       49 89 c7                mov    %rax,%r15
  400d3c:       83 c3 03                add    $0x3,%ebx
  400d3f:       41 83 c6 04             add    $0x4,%r14d
  400d43:       bf 64 1f 40 00          mov    $0x401f64,%edi
  400d48:       89 de                   mov    %ebx,%esi
  400d4a:       44 89 f2                mov    %r14d,%edx
  400d4d:       33 c0                   xor    %eax,%eax
  400d4f:       41 89 1f                mov    %ebx,(%r15)
  400d52:       45 89 77 04             mov    %r14d,0x4(%r15)
  400d56:       4c 89 7c 24 18          mov    %r15,0x18(%rsp)
  400d5b:       e8 e0 fc ff ff          callq  400a40 <printf@plt>
(snip)

 うん、さすがに無理ですね。

 でも、即値で返すのは無理としても、なんか妙に無駄なコードを吐いている気がする・・・?

  400d1d:       c7 40 04 04 00 00 00    movl   $0x4,0x4(%rax)
  400d30:       44 8b 70 04             mov    0x4(%rax),%r14d

 みたいなコード吐いてるけど、下のmov、なんで%r14dに$0x4を即値で代入しないんだろ?

 あ、即値だと命令長が長くなっちゃうのか。速度はどっちがはやいんだろ?このあたり、まだx86の気持ちに慣れてない感じがするなぁ。

 しかし、x86系人外は、ステップ数だけじゃなくて命令長も意識してんのかなぁ。そういう意味ではRISC系人外よりも人外度が高い気がする。


1月21日(木)

 最近、Pimplイディオムというのを知った。クラスの外から呼ばれたく無い関数はprivateにするが、 そのprivate属性はユーザが上書きできてしまう。こんな感じ。

#ifndef hoge_h
#define hoge_h
#include <stdio.h>
class Hoge{
  public:
    void public_func(void);
  private:
    void private_func(void);
};
#endif
#include "hoge.h"

void
Hoge::public_func(void){
  private_func();
}

void
Hoge::private_func(void){
  printf("Hello\n");
}

 private_funcが外から呼ばれたく無い関数。public_funcがインタフェース。 で、これを先にコンパイルしておく。

$ g++ -c hoge.cc

 これは、(今回は*.oだが)ライブラリとして*.aとヘッダファイルをユーザに提供することを模擬してるつもり。 さて、ユーザにはhoge.hが提供されるので、それを見るとprivate_funcという関数があることを知る。 で、こんな感じで直接呼べてしまう。

#include <stdio.h>
#define private public  //private属性をpublicで上書き
#include "hoge.h"
#undef private

int
main(void){
  Hoge h;
  h.private_func();
}
$ g++ test.cc hoge.o //怒られない
$ ./a.out
Hello

 これは、C++のprivate/publicの属性はバイナリ(*.oとか*.aとか)に含まれておらず、private属性を守るかどうかは、その関数を呼ぶコードをコンパイルする際のコンパイラの責任になっているから。ここでは#define private publicを使ったが、どうせヘッダファイルが提供されているので、そこを直接private→publicに書き換えれば良い。

 で、これを防ぐのがPimplイディオム。クラス内にprivateなクラスImplを作り、その実装をccに逃がすことで、privateな関数の定義を*.hに書かずに済む。こんな感じ。

#ifndef hoge_h
#define hoge_h
#include <memory>
class Hoge{
  public:
    Hoge(void);
    ~Hoge(void);
    void public_func(void);
  private:
    class Impl;
    std::unique_ptr<Impl> impl;
};
#endif
#include <stdio.h>
#include "hoge.h"

class Hoge::Impl{
  public:
    void private_func(void);
};

Hoge::Hoge(void) : impl(new Hoge::Impl()){
}

Hoge::~Hoge(void){
}

void
Hoge::public_func(void){
  impl->private_func();
}

void
Hoge::Impl::private_func(void){
  printf("Hello\n");
}

 ユーザに提供されるのはhoge.hのみであり、そこにはImplの実装に関わる情報が全く書いていないため、private_funcについて完全に隠蔽される、というもの。

 このPimplイディオム、実装の隠蔽とソース間の依存性減少の両方の役割を持つ、ということだが、後者はともかく前者の意味あるのかなぁ、というのが正直な印象。なんというか、道具立てが大仰過ぎる。

 単にprivate情報を隠蔽したいなら、hoge.ccのコンパイル時に使うヘッダファイルと、それを使うユーザ向けのヘッダファイルを分ければいいだけじゃないのかなぁ。最初の例ならこんな感じ。

#ifndef hoge_h
#define hoge_h
class Hoge{
  public:
    void public_func(void);
};
#endif
#include <stdio.h>
#include "hoge_public.h"

int
main(void){
  Hoge h;
  h.public_func();
}

 ユーザに提供されるhoge_public.hにはprivateの情報がごっそり無い。どうせヘッダファイルには「ユーザが使う可能性がある関数のプロトタイプ」のみ書いてあればいいのでこういうことができる。っていうか、これでソース間の依存性減少も実現できる気がする?ヘッダを二つ扱わなきゃいけないのがアレだけど。

 というか、privateな関数を絶対使わせたくないとかそういうケースにはC++は向いてない気がする。オブジェクトファイルにはそういう情報が入っていないので、ある関数をprivateとして扱うかどうかは、「その関数を使うコード」のコンパイル時に決定されるから。 もしprivateな属性をぜったい守らせたい場合は、「その関数」をコンパイルする際にアクセス制限が決定される言語処理系を使うべきな気がする。

 そもそも「アクセス制限を絶対守らせたい状況」なんて発生するのかなぁ?ユーザが明示的にprivateをpublicで上書きして問題起こしたとしても「知らんがな」でいいじゃん。それに、「ユーザが明示的にprivateを取り消したい状況」が発生したということは、クラス設計がおかしいということなわけだし。

 わりとヘビーなタスク(SE仕事)を抱えていて、ちょっと日和っていたんだけど、いずれやらなければならないし、ずっとタスクリストにあるのもストレスなので、今日腰を据えてやることにする。

 とあるシステムがあって、それが古くなったので更新する、という話になったとする。 その作業自体は簡単なので、自動化も簡単な気がするじゃないですか。ちょっとプログラムかじった人だと 「エクセルのマクロで一発でしょ?」みたいな。だけど、システムには必ず例外処理を入れないといけない。 「誰かが入力間違えた!」とか、「現実と合わない!」とか、そういうことが絶対起きるので、それに対する対応策を容易しておかないといけない。また、権限の切り分けも大事で、何か起きる度にadmin権限が必要になるシステムは使い物にならない。admin、管理者、ユーザと、少なくとも三種類のロールに切り分け、誰が何を触れるかを規定しなければならない。 また、新システム移行は誰がいつやるかとか、その際に古いデータどうするかとか、考えなきゃいけないことは無限にある。 そういうのを全部ちゃんと考えたり、その後の「保守」を考えたりすると、システム開発、更新というのはわりと大変だったりする。

 システム構成も問題。「ウェブシステム+DB」にするか、「ローカルシステム+DB」にするか、「ローカルシステムonly(データは生で保存)」にするか、エクセルマクロでやってしまうか。それは規模や用途、使用頻度、どんな人が触るかなどによって違う。 そういうシステムの規模/特性に応じて「どこまでやるか?」を考えるのがSEの仕事なわけ。

 ・・・ということをここに書いてもしょうがないんだけど、まぁ自己満足というか、(研究できてないことへの)自己弁護というか。


1月20日(水)

 最近またAIが流行ってるのかな。AI関連のニュースに触れることが多い気がする。第5世代コンピュータ関連の資料をあさってた時にも、「AIブームは20〜30年おきにやってくる」なんて言説を見たな。

 AIでも機械でもなんでも良いんだけど、歴史に学ぶと「◯◯は20年後には(AIを含む広義の)機械に仕事を奪われて消滅する」的な予言の信頼度は20年後の天気予報くらいに思っておいた方が良い、ということがわかる気がする。「スパコンでの並列プログラム/チューニングはすぐに自動化されるからプログラマは不要になる」と言ってる人は今もいるし、15年前(?)にも確実にいた。並列プログラミングとしてFortranやC++なんかは滅んで、LISPみたいなのが主流になる、的なことを言ってた人もいた気がする。コネクションマシンユーザだったのかな。

 20年後はどうか知らないけど、少なくとも現在機械化されているべき仕事が機械化されていないのはどうにかならんのかな。21世紀にもなって人間がゴミの分別をしたり洗濯物たたんだりしてるのってどうかと思う。あと、論文等の統一的なデータベースが無いのがストレス。自分の論文のdoiをそこに全部登録し、そこに予算タグをつけておくと、予算タグから逆引きして、その予算で書いた論文がすぐに取れるシステムなんて必須だと思うし、そんなの数億もあれば作れると思うんだけど。数十億へんなものに突っ込む前に、論文データベースシステムを作ると、それがちゃんとしていれば研究者の手間を大幅に省いて、結果的に研究成果増につながると思う。まぁ、これを国の予算で変なところが作ると「ちゃんとしてない」DBになって、逆に手間を増やすことになるのが目に見えているが・・・。

 自動化と言えば、少なく見積もって1000人以上からの回答を期待している思われるアンケートを数十ページのワードファイルで送るってどういうアレなんだろうか。1000人の人の時間を数十分奪うことがどれだけ罪深いことか。しかもその後、手動で集計することになるわけだし・・・。こういうの見てるとIT(最近はICTって言うの?)は技術ではなく意識改革だなぁ、と思う。

 tanakhさんもSC15に参加してたのか。ブース見に行けばよかった(ミーハー)。


1月19日(火)

 物性研スパコンシステムに関するウェブアンケートの締め切りが1月24日(日)までとなっております。まだ回答されていない方は是非ご協力をお願い致します。3分から5分で終わる匿名のアンケートです。

 僕はなんでも「応用」にこだわるのは良くないと思う。研究は「面白いから」「それは人類が知るべきことだから」という動機でやって良い。ただし、研究者は「その研究にかかったお金」は把握しておく義務があると思う。例えば物性研スパコンで144ノードをぶん回すのは、調達費用や電気代を考慮するとわりとまとまったお金になる。そのお金は税金で賄われており、そういう計算資源が存在すること、存在し続けることはまったくもって自明なことではありません。必要なら必要だと言い続けないとその計算資源は消えます。もちろん不要だという意見もあるでしょう。いずれにせよ、みなさんの声をお寄せ下さい。

 某コンパイラに要望を提出する機会があったので、おそろしく多忙だったが、ちゃんとまとめて送った。 コンパイラに文句を言う以上、その不満の原因をできるだけ詳しく調べてフィードバックするのはユーザの義務であろう。 今回送った内容をここに載せて良いか微妙にわからないので載せない。

 なんというか、正直に言って世界でもユーザが少ない石やコンパイラの生命線って、極少数の熱心なユーザによる情報公開や交流にあると思うんだけど。まぁその、ねぇ?


1月18日(月)

 とある方に連絡を取りたくて、ウェブなり資料なりその人の書いた論文なりを調べたのだが全くメールアドレスが見つからない。 そのうち、以前のイベントでご一緒した時に名刺交換したことを思い出し、名刺入れを漁ったら出てきてホッとした。

 なんか、とある組織の研究員は個人ページも原則持たないし、個人メールアドレスもウェブに載せない、という方針っぽいんだけど、(建前上)終身雇用ならいざしらず、任期付きでいずれどこかに巣立っていくことが想定されている研究員にそういう体制はあまり良くないのではないかなぁ。その研究員が関わった論文一覧、とかもすぐには見つけられないし・・・。

 研究者が全員個人ページを持つべき、とは思わないけど、夏の学校での講演とかこれまでのセミナーのスライドみたいな、論文以外のアクティビティって結構あるわけだし、そういうのって選考の参考になったりしないのかなぁ。僕は人事選考したことないからわからないけど、僕が選考に携わるなら、まずその人の名前でググると思う・・・。

 研究活動を紹介する個人ページを持つべきかという話、もういちど考えたんだけど、無いほうが良い気もしてきた。採用についてアピールできるポイントは全部応募書類に掲載されているはずだし、それ以外でウェブ、特にSNS系で発信した情報が採用にプラスになると思えないというか、マイナスになることが多い(もしくはマイナスになるデメリットが大きい)気がしてきた。

 僕が実際に目にして「これはまずいな」と思ったのは、「自分が応募した公募に、実際に採用された人をdisる」というもの。「採用された人よりも自分の方が研究業績、教育面いずれも優れているのに納得行かない」と直接的なものから、「(自信があった公募に落ちて)採用される人が自分よりも圧倒的に業績が優れていますように」と言う間接的なものまでパターンは様々。僕が見たのはTwitterだったけど、半クローズドなSNSでもそういうのは多いんじゃないかな。僕は人事に関わったことはないけれど、これは本当にまずいと思う。Twitterアカウントに実名や所属が書いてないので匿名のつもりなのかもしれないけれど、どんなに気をつけてても、ある程度以上の期間において特定のIDと紐付けることができる発言があったら本人特定なんて簡単なんだよ(例えば、これまでの発言から専門がある程度推定できて、「今日は柏」といったつぶやきからどの研究会に出ているかと、柏所属では無いことがわかり、「発表おわった!」とかから発表者リストにいることがわかり、それを複数の研究会でやるとDiffをとれば本人特定終了、みたいな)。

 そうでなくても、深夜に研究している旨のつぶやきから「研究熱心」と思われるか「生活リズムができていない」と思われるかはわからないわけで、どこで地雷を踏むかわからないし、ネットには登場しない方が無難か・・・。まぁそれでも連絡先と論文リストくらいはウェブですぐにわかるようにしておいて欲しいけど。

 「sinusoidal」の発音って「サイナソイダル」なのか。これまでずーっと「シヌ(シニュ)ソイダル」って言ってたわ。 そういえば「simultaneously」も「シミュルテイニアスリー」と言ってた気がする。発音サイトで調べたら「サイマルテイニアスリー」に近いな。「simulation」を「シミュレーション」と言うから、それにひっぱられたのかなぁ。

 あ、ネット、特にSNSに出現することが採用についてデメリットになる例をもうひとつ思い出した。研究のことは論文で評価すべきだし、研究の進捗や環境についての愚痴を言うのは良くない、という思いから、普段見てるドラマとか映画とかの話題だけをブログに書いてたら「ドラマや映画ばかり見てないで研究したら」みたいなことを言われた人とか。この事例を見て「もしウェブに顔を出すなら、その全てが採用に関する判断材料になるのだから、そう意識すべき」と思うか、「研究者の能力は業績のみで判断すべきで、そういった二次的な要素を考慮すべきでない」と思うかは人によるが、前者の立場をとる人が採用の側にいる可能性は有意に存在するので、自衛のためにも余計なことは書かないほうが無難か・・・。

 というようなことをここに書くことが果たして「余計なこと」かどうか考えだすと微妙だなぁ。特にプラスになると思えない以上、マイナスにはならなくても「余計なこと」なんだろうな。

 今日、ポスターパネルが届いたので、納品に立ち会った。これまで使ってたポスターパネルは「ベース」「ポール」「パネル」を利用するたびに組み立て、分解しなければならない。あと「ベース」「ポール」キャリアが死ぬほど重い!こんなかんじ。

 何キロあったんだろ?100キロや200キロじゃ聞かないくらい重かったんじゃないかなぁ。ベース一個でも相当な重さがあったから。

 今回導入されたパネルはこれ。

 軽い、軽いぜ!自立型でキャスター付き。片手で運べるほど軽く、運んでる時には手首の力だけで方向転換できる。なにより自立型なので毎回組み立て、分解の必要が無い!収納も6Fになった。ほとんどの研究会のポスターセッションは6Fでやるので、6Fからガラガラ運んでそのまま並べ、終わったらガラガラ戻すだけ。エレベータを経由する必要無し。レイアウト変更も思いのままだぜ。

 ここの読者(どれくらいいるか知らないけど)の参考のために型番も書いておこう。「イトーキ クロスパネル(1連) FSK-28AGC-Z5T5 (右下の奴)」。最後のT5は色(グレー)の指定だと思う。基本的に在庫は無く、受注生産。両面布張りでピンが刺さる奴で、磁石は使えない。キャスターがあっても重ねて収納できるので、さほど場所は取らないしとにかく軽い。理研AICSにあるポスターセッション用のパネルもこれです。皆さんもこれで素敵な研究会ライフを!

 昼から3時くらいまでポスターパネルの納品につきあってて、その後7時くらいまで修論発表練習会、的な。


1月17日(日)

 NOP


1月16日(土)

 NOP


1月15日(金)

 スライドとかに擬似コード片を書くときはFortranっぽく書くことが多いんだけど、 Fortranを書かなくなって10年以上たつので、いま見返すと間違いがある。以前書いたスライドにこんな記述が。

DO i=1, N-1
  DO j= in list[i]
    f = force(q[i],q[j])
    p[i] = p[i] + f * dt
    p[j] = p[j] - f * dt
  END DO
END DO

 Fortranの配列は[]じゃなくて()だったわ。まぁinとか使ってる時点でFortranじゃないけど。

ちなみにFortranっぽく書いているのは、C/C++だとブロックが{}になってスライドで読みづらいかなと思って。 あと、DOやENDDOを大文字で書けるというのもブロックの視認性を上げるかもしれない。

 訳あってJavaScript書いてたんだけど、JavaScriptって整数同士の割り算が整数にならないのね。 これはわりと珍しいんじゃないかなぁ。C/C++/Fortran/Java/Ruby/Pythonでは、整数同士の割り算は整数に丸められる・・・と思ったら、これはPython2とPython3で挙動が違うとのこと。あとはPHPが整数にならないのか。あ、Perlもだ。

 まとめて見よう。整数同士の割り算が・・・

 あ、整数同士の割り算が浮動小数点数になる言語ってわりとあるのね。


1月14日(木)

 忙しい忙しい。

 「忙しい、忙しい」という人ほど実際にはさほど忙しくなくて仕事もできない人で成果も出ない人でしかもモテないんだそうで。


1月13日(水)

 ずっと前はちゃんと動いていたプログラムが動かなくなった。具体的には、とある最適化プログラムが、急に成績が悪くなった。このプログラムは最適化にモンテカルロ法(メトロポリス)を使っていて、評価関数の値にマイナスをかけたものをエネルギーとしている。で、調べてみると、そのエネルギーの評価にミスがあることが判明。直すと正しく動作しているように見える。

 さて、問題は「このミスはいつから入ったか」である。このプログラムはgitで管理しているので、git blameをすることになるが、さすがにコマンドラインから何度もgit blameしたくない。で、そんなこともあろうかと、少し前にtigを入れてあったのだった。まず、問題のファイル名を指定する。

$ tig hogehoge.cc

 すると、hogehoge.ccに対するコミット一覧が出てくるので、気になるコミットでリターンキーを押すと、そのコミットでのdiffが表示される。するとhogehoge.ccを作った時点でバグが入っていることがわかった。もともとこれはhoge.ccの一部に入っていたもので、そこからリファクタリングで分離したもの。というわけでtig hoge.ccをして、各コミットについてdiffを調べること数分。バグが入った瞬間を見つけた。

 ここだ。この赤いとこ(削除)までは正しくて、緑のとこ(追加)でバグが入ったんだ。具体的には、外部の関数を生呼びしているところを、クラスのメソッドにラップしたところで、引数を間違えていた。ラップメソッドを作った際、間違いもラップされてしまって見えなくなっていた。ログによると2014-10-10 19:17まで正しくて、2014-12-12 18:32の修正でバグが入ったのか。うわ、一年以上このバグを放置してた・・・。

 しかしtig便利だな。git blameで同じことをやってみたらすげー面倒くさい。あまりGUI系ツールは好きじゃなかったんだけど、例えばTortoiseSVNとかTortoiseGitとか、使ってみるといろいろ便利なのかなぁ。

 久々にジョブを投げたんだけど、スパコンでジョブが流れてると心が落ち着く。っつーかジョブを「久々に投げ」てる時点で数値計算屋としていろいろアウト。


1月12日(火)

 年末から恐ろしく忙しく、やりたいことがほぼ何もできない状況が続いているのだが、その忙しさの成果は外から全く知覚できないタイプの仕事なのがとても悲しい。

 研究者の情報発信についていろいろ考えてしまう。SNSとかブログとか。一般的に言って、勤務時間内に勤務内容に無関係のことをしてはならないわけで、SNSなどでの情報発信もその枠組で考える必要がある。では研究者はどうか。例えば「論文出ました」「◯月◯日にどこそこで発表します」といった情報発信はほぼ間違いなくOKであろう。研究に関連する議論も多分OK。学会や研究会の感想の発信も業務と言って良いだろう。しかしプログラムを組んでて気になったことを調べた結果はだいぶ怪しくなってくる。例えばstaticキーワードがどんなコードに翻訳されるかを調べるのは?Windowsのメモ帳の改行について調べてQiitaに投げるのは?このあたりはまだ「数値計算屋としてプログラムに関連する情報収集+発信をするのは許容」と言えるかもしれない。では、「宇宙に惑星は7つしかありえない」と言った哲学者が誰か調べるのはどうだろう。このあたりはギリギリ「科学」カテゴリには入るかもしれないが、研究カテゴリからは、ほぼ外れている。誰かが「業務と無関係だ」といえば、僕は戦うことなく「そうですね」と言うと思う。

 そもそもこういう文字通り「つぶやき」「ひとりごと」みたいなものを大学のサーバで公開して良いのか?誰かが「これは業務内容と無関係でけしからん」と言ってきたら、僕はすぐここを閉じると思う。そんな思い入れのあるものでもないし、科学者の社会的責任において何かを発信しているわけでもない。どこか別のサーバでこっそり続けるかもしれんけど、実名発信はもうしないだろう。

 一般的なサラリーマンは、広報担当でも無い限り業務時間中にブログの更新/SNSの発信は許されないであろう。研究者でも、一般企業の研究所の研究者が情報発信をするのは厳しく制限されていることが多いと思う。大学の研究者がブログやSNSなど、ウェブを通じた情報発信を行うことが多いのは、いろいろ歴史的な理由もあるんだろうけれど、よく考えるとよくわからない。研究者の情報発信は、別に特別に認められた権利でも義務でもない(と、あくまで個人的にはそう思う)。税金を使った結果を紹介するアウトリーチは別枠で考えるべき。

 で、僕の情報発信など全く価値は無いけれど、科学者の責任において、不正を告発したり、科学の名において行われる非科学的な何かを糾弾したりしている研究者が情報発信できなくなるのは、社会的に見れば損失だと思う。そういう時に、そういうことができる「根拠」を与えておくのは重要だと思う。そういう意味で、いわゆる「20%ルール」は有用だと思う。特にITベンチャー系企業(Googleが有名)が採用しているこのルール、要するに「業務時間の何割かは業務に無関係なことをしてよい」というもので、これが業務時間中の私的なブログ更新、SNSなどができる根拠というか、拠り所になっている。

 なんかいつもながらとりとめのない文章になった。しばらく前から「税金で雇われている研究者はどうあるべきか」をずっと考えていて、まだちっともまとまっていない。僕は科学には多様性が重要だと思っていて、そのためには「とにかく自由に研究をする研究者の数を増やす」のが大事だと思うんだけど、なんか「いまはこのテーマが大事だ!」みたいな「戦略」にもとづいて大きなテーマが決まり、さらにそのテーマを遂行するためのサブテーマがわりとカッチリと決まり、研究者がエフォート100%でその「わりとカッチリとしたテーマ」に専念する、というパターンが増えてきて、「研究者」とはなんだったんだろう、と思って。でも、「それじゃどうすべきなのか?」と言われるとそれもよくわからなくて。そこにSNSでの発信規制の話を見かけて・・・。


1月11日(月)

 NOP


1月10日(日)

 NOP


1月9日(土)

 NOP


1月8日(金)

 ローカル変数として宣言されたstd::vectorをstaticにしたコードを見て、「これはstaticにしてもmallocが毎回呼ばれちゃうんじゃないの?」と言ってしまったのだが、「呼ばれません。コンストラクタは一回だけです。シングルトンはそうやってできるわけですし」と言われた。確かにその通り。具体的にはこんなコード。

void func(int size){ static std::vector<int> v(size); }

 このコードで、size(わりと大きい)によるmallocが走るのは最初に呼ばれた一度だけ。従って、こんなコードを書けば当然バグる。

#include <iostream> #include <vector> void func(int size){ static std::vector<int> v(size); for(int i=0;i<size;i++){ v[i] = i; } std::cout << v[size-1] << std::endl; } int main(void){ func(1000000); func(2000000); }

 まず思うのは、キモい。すごくキモい。intやdoubleといったローカル変数にstaticをつけるのはまぁ許容というか、感覚的にはわからないんでも無かったんだけど、クラスのインスタンスがローカル変数でstatic宣言できるのは非常に気持ち悪い(いや、自分でもローカル変数でstaticなvector使ってるんだけどさ)。

 で、この気持ち悪さのまま、もう一度よく考えるとstaticなローカル変数もキモい。要するにC++におけるstaticローカル変数というのは、「スコープが限定されたグローバル変数」なのであって、そういう意味ではコンストラクタが一度しか走らないのも理解できるのだが、それでも気持ち悪い。さらに言えば、staticローカル変数が初期化されるのは初めて関数が呼ばれた時なので、最初に初期化されるグローバル変数とは動作が異なる。

 そういう意味でローカル変数はstatic宣言できちゃダメだと思う。もちろんJavaはできない。Javaはさすがに「Better C++」なだけあって、僕がC++に感じる気持ち悪さをいろいろ解決しているんだよなぁ。

 そもそもstaticな変数ってどうやって実現してんだろと思って、

void exfunc(int);
void
func(int i){
  static int j = i + 1;
  exfunc(j);
}

みたいなのを食わせてみたら、

LFB0:
        cmpb    $0, __ZGVZ4funciE1j(%rip)
        pushq   %rbx
LCFI0:
        je      L8

 みたいなのを吐いてる。要するにstaticな変数それぞれ全てに対応するグローバル変数(フラグ)を用意し、それが0であるかどうかチェックすることで初期化されたかどうかチェックする・・・と。ものすごく普通な解決で逆に驚いた。 で、問題はL8、つまり初期化されていなかった場合の初期化処理が妙にややこしい。こんなの。

L8:
LCFI2:
        movl    %edi, %ebx
        leaq    __ZGVZ4funciE1j(%rip), %rdi
        call    ___cxa_guard_acquire
        testl   %eax, %eax
        je      L6
        leaq    __ZGVZ4funciE1j(%rip), %rdi
        addl    $1, %ebx
        movl    %ebx, __ZZ4funciE1j(%rip)
        call    ___cxa_guard_release
        movl    %ebx, %edi
        popq    %rbx
LCFI3:
        jmp     __Z6exfunci

なんか___cxa_guard_acquireとかcallしてる。調べたら、これはスレッドセーフにするための関数。そうか、staticなローカル変数を持つ関数を、複数のスレッドが同時に触ったらおかしくなるもんな・・・。後、testl %eax, %eaxってなんじゃらほいと思ったら、これはeaxが0かどうかを調べるコードだそうな。StackOverflowに同じ疑問があって、cmp eax,0よりコードが短くなるからという回答が。なんかこういう命令セット、いかにもCISCという感じがする。もうCISC/RISCとか死語なのかもしれんけど。

 で、気になったんだけど、複数のstatic変数があったら、当然それぞれスレッドセーフにしなきゃいかんわけだけど、それってどうやって区別してるんだろ。cxa_guard.cxxのソース見る限り、uint64_tのguard_objectを引数にとってて、それで「何が」初期化されたか判別してるっぽい。このコードだと8バイト整数の__ZGVZ4funciE1j(%rip)がguard_objectっぽい。どうやって使ってるのかはわからないな・・・。

 あ、わかった。8バイト整数を構造体みたいに使って、最初の1バイトが初期化フラグ、次の1バイトが現在使われているかなのか。 それなら4バイト整数で十分だと思うんだけど、4バイト中2バイトも使うと後で不安だから、将来のために8バイト用意してあんのかな。それなら最初の1「ビット」とかにすれば良いだけだと思うんだけど・・・。

 なんというか、スレッドセーフと例外安全は闇。マジで闇。


1月7日(木)

 マイナンバー関連、手続きした。

 CMSI計算科学技術特論C。今日は千葉 滋さん。Javassist作った人。テーマが面白そうだったので見てみた。この人の文章、どっかで読んだ記憶があるなぁ。


1月6日(水)

 E. T. Bellの「数学をつくった人々」では、ヘーゲルが「惑星の数はまさに7つでなければならず、8つ目の惑星探索はおろかな時間つぶしにすぎない」と言ったとされているのだが、未だにその原典にあたっていない(当時、ハーシェルが7つ目の惑星である天王星を見つけており、8つ目の探索が行われていた)。しかし、それに近いことを言った人を見つけた。フランチェスコ・シッツィ(Francesco Sizzi)という天文学者で、黒点の移動を発見した人らしい。時代的にはガリレオ・ガリレイと同時代なので、ヘーゲルやハーシェルよりだいぶ前。ガリレイが木星の衛星を発見したと発表した際、「宇宙に星は7つでなければならず、木星に衛星は無い」という主張が書かれた「天文学的考察」を出版したらしい。その該当部分の英語訳をいい加減に和訳してみる。

人間の頭には7つの穴(二つの目、二つの鼻の穴、二つの耳、そして口)が開いている。 同様に主は宇宙に二つの善の星(木星と金星)、二つの悪の星(火星と土星)、二つの光の星(太陽と月)、そして一つの中立の星(水星)を作られた。最後に錬金術士は7つの金属を星々と関連付けた。金は太陽、銀は月、銅が金星、水銀が水星、鉄が火星、錫が木星、鉛が土星である。以上、様々なことを考慮するに、星の数は7つでなければならない。多くの人が7つの星に対応した曜日を採用しており、もし星が増えたら全てが大混乱に陥る。さらに、木星の惑星は裸眼では見えず、従って地球にはなんら影響を与えない。従って役に立たず、存在もしない。

 おそらく原文はラテン語だったのだと思われるが、英訳だけを読むとシッツィが「たとえ木星に衛星があったとしても、そんなものはなんの意味が無い」という意図だったのか、「衛星があったとしても意味が無いのだから、そんなものを神が作るわけが無く、従って存在しないはずである」と論じたのかはわからない。とにかく、当時知られていた星は7つであり、それぞれ全てが曜日と対応している(日月火水木金土)。聖書も神は世界を6日で作って一日休んだと書いてあるし、7は特別な数字であった。数秘術、錬金術、占星術は複雑にからみあっており、当時の「常識」の一部でもあったはずで、先の発言はこの背景を考慮する必要がある。

 結局、E. T. Bellがシッツィの発言をヘーゲルと混同したか、ヘーゲルがシッツィの発言に近いことを実際に言ったのかはわからない。ただ、天動説が常識だった時代に「地球から見える星は7つでなければならない」という思想が、地動説が常識になった後に「地球を含めて太陽系の惑星は7つでなければならない」という思想に変わったであろう、ということは想像がつく。

 そういえば人間の顔には7つの穴があるというエピソード、どこかで見たと思ったが、アレだ、荘子の「渾沌の穴」だ。南海の帝と北海の帝が、中央の帝である「渾沌」にもてなされる。渾沌の顔には穴が空いておらず、二人の帝は恩義に報いるため、一日に一つずつ穴をあけていったが、七日目、最後の穴が開いた際、渾沌は死んでしまった、という話。


1月5日(火)

 「今年は研究がんばる」と思いつつ、既に新年始まって二日間、まったく研究時間が取れなかった。

 理由はわかっている。雑用の処理能力、特に「雑用を抱えている時に、それを一時的に頭から追い出す能力」の不足。しかしそれは「ダイエットがうまくいかないのは適切な食事制限と運動が足りないから」という種類の理由であり、「ではどうすべきか」につながらない。


1月4日(月)

 新年早々忙しい。


1月3日(日)

 NOP

 スタッドレスに履き替えた。


1月2日(土)

 NOP


1月1日(金)

 NOP

 明けましておめでとうございます。今年もよろしくお願いします。

 昨年、あまり研究できなかったこともあって自信を失っていた。自信を持つには結果が必要であり、結果を出すには努力が必要。学生の頃は努力の時間はたっぷりあったので、「努力しても成果が出ない自分」に凹んでいたが、最近は「そもそも努力する時間が取れない自分」に凹んでいる。研究時間を確保するのも研究能力のうち、と言われればそれまでなのだけれど。

 そんななか、かつての教え子からの年賀状に「先生の教えを受けたことが今も誇りです」的なことが書かれていた。

 僕の研究は役に立たない。というか役に立つことを直接の目的としていない。ではなぜそんなことを税金でやるのかと問われれば、それを知ることが人類の義務だと思っているから。つまり、この研究をすることそのものが人類という種の価値向上に貢献する、という論理。であるならば、研究者も税金で食べている以上、その存在自体が人類の価値であらねばならない。そんな価値が本当に自分にあるかどうかはともかく、そういう存在を目指さなければならない。

 彼を失望させてはならない。彼が将来も僕から「教えを受けたことが今も誇り」であり続けられるように、僕はがんばらないといけない。そういう年賀状をもらったことを僕の誇りとし、今後も研究に励みます。ありがとう。


トップページへ戻る