soy-curd's blog

へぼプログラマーです [https://twitter.com/soycurd1]

なぜシン・ゴジラはナックルウォークを経ずして二足歩行を獲得することができたのか

(この記事は明確にシン・ゴジラのネタバレを含みますので、未視聴の方は閲覧しないでください)

はじめに

 現生生物で二足歩行を行う生き物といえば、真っ先に鳥類が思い浮かぶが、その二足歩行の起源については恐竜にまで遡る。鳥類の起源は恐竜の中でも、多くの種が二足歩行をしていたとされる竜盤目獣脚類とされているからだ(これはティラノサウルスを含む群になる)。そして、彼らがどのようにして二足歩行を獲得したかについては、どうやら以下の論文に目を通したかぎりははっきりとした定説はなさそうだ。

https://www.dinosaur.pref.fukui.jp/archive/memoir/memoir010-055.pdf (恐竜の共通祖先は二足歩行だと思われていたが、実は四足歩行なのではないかという議論がされている)

 さて、公開中の映画シン・ゴジラでは、獣脚類によく似た見た目のゴジラが、作中で二足歩行を獲得した。この二足歩行に至る描写がとてもすんなりと頭に入ってきたので、非常に感動した(もしかしたら元ネタがあるのかもしれないけれど)。つまり要約すると、ゴジラは前足が退化していたため、四足歩行することができず、地上では二足歩行せざるを得なかったのだ。

問題意識

 まず、そもそもなぜこんな疑問が生じるかについて理解できない方もいるかと思われるので、問題を共有したい。例としてヒトを挙げる。問題は、「ヒトはどうやって(直立)二足歩行を獲得したのか」。その答えは、とてもざっくりと進化論を援用して言うと、「二足歩行可能な形質をもった個体がたまたま発生し、それがたまたまその環境で生き残ったから」となる。しかし、果たして四足歩行しているサルからいきなり二足歩行する生物が生まれるのだろうか。だとしたらなぜ二足歩行の哺乳類は珍しいのだろうか。そのような疑問に答える一つの方向性として、それらの進化の隔たりを埋める中間的な形質を持つ種が存在した、と仮定することができる。それは上記の文脈で言うと、ゴリラ等が行うナックルウォーク(拳をついて歩くこと)、ということになる。樹上生活を行っていたサルが、前足を枝を握るために用いるようになる。前足の形状は歩行には適さない。その中で地上に降りたもの(ゴリラ)が、前足を握り歩行するようになる。しかしそのナックルウォークだとあまりにも移動コストが高い。そのために、森が失われ歩行が優位になる環境では、直立二足歩行というナックルウォークに比べると移動コストの低い手段を用いることのできる生物が、新たな種として固定される。...果たしてこれが明快なストーリーだろうか? 二足歩行なんて不安定な移動法を取るくらいならナックルウォークのほうがましではないのか?(少し古い記事だが、http://sicambre.at.webry.info/200710/article_17.html ナックルウォークは直立二足歩行より後という内容もある)

https://www.youtube.com/watch?v=rVlhMGQgDkY


Atlas, The Next Generation

(近年見られる四足歩行から二足歩行への進化の例)

 以上のように、二足歩行について少し考えるだけで頭が混乱してくるのだが、シン・ゴジラの中では二足歩行の獲得は明快に示される。なにしろ、視聴者の目の前で得体のしれない生き物がどんどん進化していくのだ。そして、地上にでてきたそれは当初、前足はひれ状になっており、後ろ足だけが発達している。移動方法は匍匐だ。そして物語は進み、ついに、その両足で立ち上がる。あのやたらと気持ち悪い謎の生物がやっと二足歩行を獲得したのだ。  

ゴジラにおける二足歩行の獲得

 ゴジラは二足歩行を獲得する順序において、匍匐→四足歩行→二足歩行という脊椎動物の王道を無視し、ひとつ飛ばしに匍匐→二足歩行という進化を遂げた。こここでの進化は、「すでに退化してしまった前足を歩行用に用いる」というオプションではなく、「すでに発達している後ろ足のみでの歩行」というオプションが用いられている。おかげで、匍匐から二足歩行への中間的な形質である四足歩行(ヒトの説明で言えばナックルウォーク)をスキップしている。これは明らかに、前足が退化していたおかげである。これは二足歩行を獲得する上で非常にスマートな回答のひとつだと自分は思う。シン・ゴジラ公開前に、自分は「このゴジラ前足がちっちゃい!前足がちっちゃい!」としか思っていなかったが、その伏線が回収された瞬間が、このゴジラ立ち上がりシーンだと言える。オットセイ、アシナシイモリ、ヘビ類等に準じた退化をし(有尾類のネオテニーが可能性が高いと睨んでいるが)、十分な歩行器官の無い生物だからこその、二足歩行の獲得。それを視聴者の前でやってのける映画力、さすがだ。この映画の95%ぐらいの面白さはここに詰まっている。

f:id:soy-curd:20160831033748p:plain

最後に

この記事はゴジラが四足歩行を獲得した生物(両生類や爬虫類)から進化した、という仮定にもとづき書かれているが、「単に魚から進化しただけでは?」というつっこみにはじまり、生物学的に不適切であることが確実なため(用語も適当、"中間的な形質"、とか、進化論ではなんていうんだろう?)、不備については順次指摘されたい。また、「どうしておばあちゃんのお口はそんなに大きいの?」「それはお前を食べるためだよ」的な考察(たぶんビルで視界が塞がれるから立ち上がったんだと思うが)もしていないので、そちらについても気になっていることではある。ゴジラの二足歩行に対して専門的な意見を持っている方がもしおられれば、随時ネット上に関連記事をアップしていただけると非常にありがたい。

Erlangでリスト操作(map, filter, foldl等)

今、時間があるときにErlangを触っているのだけれど、関数型デザインの言語だけあってリスト操作の関数が充実している。そこで、Erlangのリスト操作関数の内、よく使いそうなものを以下にリストアップしてみた。

map

リストの各値に関数を適用した新しいリストを返す。

map_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  AddOne = fun(X) -> X + 1 end,
  lists:map(AddOne, L1).

filter

リストの各値をフィルターしたリストを返す。

  
filter_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  IsEven = fun(X) -> X rem 2  == 0 end,
  lists:filter(IsEven, L1).

fold

リストの各値を畳み込んだ値を返す。リストの左から計算するか右から計算するかによってfoldlとfoldrがある。

fold_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  Add = fun(Acc, X) -> Acc + X end,
  lists:foldl(Add, 0, L1).
  

zip

2つのリストを合体させる。下の例だと[{1, 11}, {2, 12}, ...]のようなタプルが入ったリストになる。

zip_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  L2 = lists:map(fun(X) -> X + 10 end, L1),  
  lists:zip(L1, L2).
  

flatten

ネストされたリストからネストのないリストを作る。

flatten_test() ->
  L1 = [1, 2, 3, [4, 5, 6], 7, 8, 9, 10],
  lists:flatten(L1).
  

flatmap

値からリストを作る関数を受け取り、それを引数のリストの値に対して適用してから、flattenする。下の例だと[1,1,1,2,2,2,...]のように返る。

flatmap_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
  lists:flatmap(fun(X) -> [X, X, X] end, L1).
  

takewhile, drop while

takewhileは比較関数がtrueまでの値の入ったリストを返す。drop whileはその逆。

takewhile_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  IsLess5 = fun(X) -> X < 5 end,
  lists:takewhile(IsLess5, L1).
dropwhile_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  IsLess5 = fun(X) -> X < 5 end,
  lists:dropwhile(IsLess5, L1).

partition

比較関数でリストを分割する。

partition_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  IsLess5 = fun(X) -> X < 5 end,
  lists:partition(IsLess5, L1).
    

merge

二つのリストをソートして合体させる。merge/3はソートに用いる比較関数を引数に取れる。

merge_test() ->
  L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  
  L2 = lists:map(fun(X) -> X + 10 end, L1),  
  lists:merge(L1, L2).

JSだとunderscoreとかを使わなきゃいけないことも組み込みで入っていて便利。

Erlang -- lists

Ubuntu 16.04でcaps lockをCtrlに変更

askubuntu.com

どおりに。

  • gnome-tweak-toolをインストール
sudo apt-get install gnome-tweak-tool
  • tweak toolを起動

  • Typings -> Caps Lock Key behavio -> MakeCaps Lock an additional Ctrl

かんたん。

(ちなみにTyping -> Alt / Win key behavior -> Alt is mapped to Win keysでaltとwinを交換できたりする)

東プレ NG01B0 REALFORCE91UBK

東プレ NG01B0 REALFORCE91UBK

机の上においたボタンを押すとリアルタイムでSlack上に寿司を食べたいことを通知できるシステムを構築した

机の上においたボタンを押すとSlack上に寿司を食べたいことを通知できるシステムを構築した。

github.com

動機

寿司を食べたい時にそれをSlackで報告するためわざわざキーボードに手を伸ばすのは非常に面倒である。机の上に専用のスイッチがありそれを押すだけで寿司が食べたいことを通知できれば非常に素晴らしいユーザー体験が得られるはずだ。昔遊んでいたArduinoが家にあったので、それとSlackを組み合わせることでシステムを構築していく。

作り方

Arduino

100均に行ってボタンっぽいものを購入する。

f:id:soy-curd:20160619234139j:plain

スイッチ式のシーリングライトがあったので流用。ライトなので押すと光る。

f:id:soy-curd:20160619234206j:plain

(光る)

気合で内部のスイッチを見つけ出して配線。

f:id:soy-curd:20160619234400j:plain

内部を開けるとこんなかんじになっていた。緑と黄色のリード線は自分で結線した。

f:id:soy-curd:20160620000154j:plain

適当に抵抗を繋いでやばい電流がArduinoにいかないようにする。 回路図を示したいところだが、そもそも100均ボタン側の回路が不明なのでプレッドボード側も勘で配線した。 とりあえず5Vを直接グラウンドに繋いではいけないことがわかった。

Arduinoにコードをデプロイ。

const int SWITCH = 2;

void setup() { 
  pinMode(SWITCH, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(SWITCH) == HIGH) {
    Serial.print("1\n");
  } else {
    Serial.print("0\n");
  }
  delay(500);
}

Arduinoに繋いでシリアルモニタでチェック。"1"と"0"がボタンに応じて出力されていればOK

。出てなかったら配線とか抵抗を見直す。

Python

PySerialというモジュールがあるので、それをpipでインストール(Arduinoとの通信)。

Pythonでシリアル通信 - Qiita

こちらを参考にした。

slackwebというモジュールがあるので、それをpipでインストール(Slackとの通信)。

SlackのIncoming WebHookを用いた。異常に簡単にSlackにメッセージを流せる。

Slackにincoming webhook経由でpythonからメッセージをPOSTする - Qiita

コードはこちらを参考にした。 Incoming WebHookのURLは環境変数に格納し、実行時に読み込むようにした。

pythonを実行

import slackweb
import os
import serial
import time

url = os.environ["SLACK_OHA"]
slack = slackweb.Slack(url=url)

port = "/dev/cu.usbmodem1421"
current_oha_state = False

# ボード側は500ms間隔でserialにHIGH -> b"1", LOW -> b"0"を送信する
with serial.Serial(port=port, baudrate=9600, timeout=1) as ser:
    while True:
        # time.sleep(0.1)
        flag = ser.readline()
        # switch ON
        if (bytes(b"0") in flag and not current_oha_state):
            current_oha_state = True
            print("oha")
            slack.notify(text="スシ食べたい🍣")

        # switch OFF
        elif (bytes(b"1") in flag and current_oha_state):
            current_oha_state = False
            print("otu")
            slack.notify(text="スシいらない🍣")

        print(flag, current_oha_state)

結果

とりあえずボタンをポチポチ押す。すると、

f:id:soy-curd:20160619231258p:plain

ほぼリアルタイムでこのようになる。ギリギリIoTの範疇に入る気がする。

これで快適に他人にスシを食べたいことを通知できるようになった。 会社のCTOがArduinoの無線モジュールを入手したようなので、それを使えばボタンをPCから独立させることも可能な気がする。未来っぽい。

J・M・クッツェー『遅い男』読んだ

J・M・クッツェー『遅い男』読んだ。自転車事故で脚を一本失った老人の話だが、全体的におもしろい。中盤以降、作者みたいな人物がいきなりログインしてきて、そこから自由意志vs神みたいなかんじの話になだれこんでいくところが超良い。素晴らしい。

遅い男

遅い男

最急降下法をPythonで実装した

関数x2 + xは、どうやら最小値がひとつだけ存在するらしい。どうしてもその値を知りたくなったので、最急降下法を使ってPythonでその値を求めてみた。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random

learning_late = 0.01
loop_max = 1000

def main():
    
    initial = random.uniform(-10, 10)
    old = initial
    new = 0.0
    for _ in range(1000):
        
        # 更新式
        new = old - learning_late * diff_func(old)
        
        # 目的関数の値を確認
        y = object_func(new)
        print(y)
        
        # 値を更新
        old = new
        
    print(new, y)
        
    
# 目的関数
def object_func(x):
    return x * x + x
    
# x ^ 2 + x の微分
def diff_func(x):
    return 2 * x + 1

if  __name__=='__main__':
    main()

これを実行すると、

# x、y
(-0.5000000145792641, -0.24999999999999978)

と、xが-0.5付近の時に目的の関数が最小値となることがわかった。なるほどというかんじ。

ITエンジニアのための機械学習理論入門

ITエンジニアのための機械学習理論入門

言語処理のための機械学習入門 (自然言語処理シリーズ)

言語処理のための機械学習入門 (自然言語処理シリーズ)