2020-11-23

macOSのM1とx86-64におけるベンチマーク比較の考察

世間ではAppleの新しい製品に使われるARM64 CPUであるM1の話題でもちきりだ。ただし、日本語を話す記者というのは極めて非科学的かつ無能であり、M1の現物を手にしても、末端のソフトウェアを動かして、体感で早いだの遅いだのと語るだけだ。そういう感想は居酒屋で酒を片手に漏らすべきであって、報道と呼ぶべきシロモノではない。

と思っていたら、Phoronixがやってくれた。M1とi7で動くmacOSでベンチマークをしている。

これを考察すると、M1のMac Miniは、一世代前のi7のMac Miniに比べて、メモリ性能とI/O性能が高く、演算性能は低いようだ。このことを考えると、M1の性能特性としては、動画のエンコードやソフトウェアレイトレーシングをするには不向きだが、その他の作業は遜色ないだろう。

問題は、仮想化とRosettaを組み合わせることができないという点だ。x86-64のユーザースペースのdockerイメージをM1 macOSで実行するには、かなり大掛かりな独自の実装が必要になるだろうし、結局本番環境はGNU/Linux x86-64なので、開発者受けはよくないだろう。ただし、サーバーがARMを採用するのが一般的なれば話はまた変わってくるかもしれない。ただし、その場合もサーバーOSの首位はGNU/Linuxで揺るぎないだろうから、macOSは使いづらく、開発者はGNU/LinuxかWindows WSLを選ぶだろう。ARM64 macOSの上で動く仮想化の上で動くGNU/Linux ARM64という選択肢はあるかもしれない。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

M1で動くmacOSでソフトウェアを実行するには、ARM64ネイティブコードを動かす方法と、x86-64バイナリをRosettaという変換レイヤーを通してリアルタイムにARM64に変換して実行する方法がある。すでにある体感による報道では、Rosettaはi7よりも早いという。本当だろうか。早速ベンチマーク結果を見ていこう。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

分子動力学シミュレーションのNANDでは一世代前のi7のMac Miniと比べて変換が走っているとは思えないスコアを出す。一世代前のi7を搭載したmac Miniよりスコアが高い。ただしDNAの多重整列をするMAFFTのRosetta経由のスコアは低い。ネイティブのスコアはi7を超える。

WebPによる画像圧縮やLibRawによる画像ポストプロセッシングのスコアはi7とRosettaで遜色がない。

Zstdによる圧縮はなぜかResettaがぶっちぎりで圧倒的スコアを叩き出している。どういうことだろう。Zstdの圧縮処理は軽いので、これは演算能力ではなくメモリ帯域をベンチマークしているのではないだろうか。つまり一世代前のi7 Mac MiniよりM1 Mac Miniのほうがメモリ性能がよいのだ。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

Intelによってx86-64用に最適化されているOSRayによるレイトレーシングや画像ノイズ除去ではRosettaは振るわない。他のレイトレーシングソフトウェアのパフォーマンスを見ても、Rosettaはi7を超えているようには見えない。変換レイヤーを経由しているにしては実用的な性能ではある。

SQLiteやgitをみてみると、Rosettaはi7を大きく上回るパフォーマンスを出し、M1ネイティブだと更に素晴らしいパフォーマンスを叩き出す。これはI/O性能に律速される処理だから、I/O性能が一世代前のMac Miniに比べて高いのだろう。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

PyBenchやPHPBenchといった割と複合的なベンチマークスコアではM1はi7と遜色ないパフォーマンス、Rosettaは変換するにしてはよくやっているので実用的なパフォーマンス

KvazaarによるH.265の動画エンコードはM1がi7に圧倒的に負けている。純粋な演算性能はi7に劣るようだ。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

Java 2D Benchmark、Rosettaが強い。SeleniumをFirefoxで計測、M1が強い。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

Basis UniversalはGPU用のテクスチャ圧縮をするソフトウェアだ。このスコアはメモリ帯域に律速されると思われるが、M1が圧倒的に早い。

Botanは暗号処理のライブラリだ。M1によるネイティブ実行はできないが、Rosettaはなかなか速い。7zipやxzではM1が速い。

Fhourstonesはconnect-4というボードゲームの配置情報を計算するベンチマークで、おそらく演算自体は単純でメモリ性能に律速される処理だと思われる。M1が速い

FLACによる音声の可逆圧縮エンコードは、M1ネイティブがRosettaに負けている。FLACの実装がARM64に最適化されていないものと思われる。

Apple M1 ARM Performance With A 2020 Mac Mini Review - Phoronix

GraphicMagickのベンチマークはM1が速い。DBやサーバー環境などを模したベンチマークでもM1やRosettaが優秀な結果を出している。

2020-11-22

村上原野追悼旅行記

発端

村上原野追悼のために、11月7日から9日にかけて岡山に行ってきた。

参考:

ボレロ村上逝去

村上原野(ボレロ村上)の思い出

村上原野の訃報がプログラマーの界隈に知られてすぐに、追悼のために岡山に旅行する話が持ち上がり、10人以上もの人間が集まったが、COVID-19の感染拡大により東京から大人数で地方に移動するのは感染拡大のリスクがあるので自粛していた。

さて、冬も終わり夏もすぎて秋になり、どうやら冬に感染が拡大するらしいとのことで、今年中に行くならばそろそろ行かなければならないと思っていた矢先、妻が岡山に行くというので相乗りすることになった。GOTOトラベルキャンペーンを使い、倉敷のホテルに2泊3日の行程だ。せっかくなのでホテルは少々高くてもおしゃれなところにしようと画像を見ておしゃれそうなところに宿を取った。

11月7日

安かった時間帯の14時半に羽田空港から岡山空港に行く。飛行機の旅はあまり好きではない。荷物の検査がわずらわしいし、空港から目的地まで離れているので、結局所要時間は新幹線とそれほど変わらない。今回は現地での移動手段としてキックスクーターを持っていくことにしたが、問題なく荷物として預けることができた。

17時頃に倉敷の某ホテルに到着した。このホテルは、今回の旅で最悪の要素であった。結局、芸術性と実用性は違うということだ。見た目がよいからといって快適に滞在できるとは限らない。

このホテルは、ホテルの中では最悪というわけではない。むしろいいほうだ。見た目はきれいでおしゃれ、接客態度は申し分なく、部屋も広くて豪華だ。

では何がだめだったのかというと、実用性に劣るということだ。我々は実用性の欠如をこれから嫌というほど思い知らされることになる。

ともかく、17時にホテルに到着した我々は腹ぺこであった。無理もない。昼を食べそびれていたからだ。GOTOトラベルによる地域クーポンが1万3千円分ある我々は、使いみちのあまりないこのクーポンで、普段は食べない高くて美味しいものでも食べよう決めていた。ホテルの周辺の飲食店の中から事前に調べていた、とてもお高そうな和食を出す店に行った。ところが、あいにくとこの店は電子クーポンに対応していなかった。腹ぺこで疲れ切った我々はすぐにホテルに引き返し、ホテル内の高そうな和食レストランに行った。ここで我々はクーポンをすべて使い、かつ差額を支払ってそれなりの値段の和食のコース料理を注文した。でてきた料理は、見た目はよいが味はぱっとせず、そしてなにより量が少ない。摂取カロリーの半分ぐらいは最後にでてきたスプーン3杯程度のかぼちゃプリンがしめていたのではないかと思われるほど量が少ない。我々がそのような和食のコース料理を食べ慣れていないからそう思うのであろうか。それにしても値段に見合った価値はない。

部屋に戻った我々は風呂に入ることにした。このホテルの浴槽はかなりおしゃれだ。ただし浴槽がそのまま据え付けられていて、シャワーカーテンのたぐいも存在しない。単に湯船に浸かるためだけの浴槽だ。浴槽の中に完全に寝そべることができるほどの長さではあるのだが、幅があまりにも細すぎる。そして浴槽に浸かるとどんどんお湯が浴槽上部に取り付けられた排水口から流れていくのでお湯が少なくなる。贅沢にお湯を出しっぱなしにすればいいのだろうが、問題はお湯が供給される場所と排水口はかなり近いので、新しく供給したお湯から優先的に排水されることになる。結局、お湯を出しっぱなしにしようともどんどんお湯はぬるくなっていく。というの、部屋が広くて湯冷めが早いからだ。

からだを洗うには、浴槽の横に設置されたガラス張りのおしゃれなシャワールームを使う。欧米式で壁の上の方に取り付けられた固定式の大型のシャワーヘッドからお湯が出る。日本の風呂にありがちな椅子はない。当然、最初にでてくるのは水なのでしばらく滝行をするハメになる。別途手に取れるシャワーヘッドもあるのだが、こちらはなぜかお湯の出が極めて悪く使い物にならない。

さて風呂から上がってヒゲを剃ろうと洗面台に向かった。壁一面に鏡が設置されていてとても見た目がよい。このホテルの洗面台は大きい。あまりにも大きすぎて鏡から体が離れすぎてしまう。結果としてひげそりをしたいのに鏡を間近で見ることができない。まったくもって機能的ではない。

ベッドにはかなり分厚くてトランポリンのように反発するスプリングマットレスが使われている。これはある種の運動をするのには反発しすぎて都合が悪い。

この部屋は暗い。それもそのはずで、この部屋には間接照明しかないのだ。普通の照明がない。おしゃれではあるが実用性に欠ける。

机にラップトップをおいてホテルの提供するWiFiに接続した。しかし調子が悪い。調べてみると、どうやら帯域は問題がないがパケットロスが頻繁に発生している。これでは多くのWebサイトの利用に支障が出る。

インターネット利用を諦めて今日は寝てしまおうとベッドに移動し、寝そべりながらすこしだけラップトップを操作して気がついた。インターネットの調子がいい。パケットロスも激減した。どうやら机の付近はWiFiの電波が悪いようだ。WiFiの設置にまともな電波的な検証が行われていないのだろう。

11月8日

早朝に起床。妻は朝早くから用事があるとのことで朝食も食べずに出かけていった。私はホテルで朝食を食べてから出かけることにした。ホテルで出てきた朝食はいかにも朝食という感じで品数が多く見た目もよい。肝心の味は、特に何の感想も出てこなかった。まずくはない。美味しくもない。ただ食事というだけだ。

猪風来美術館に移動

岡山や倉敷から威風来美術館に行くには、駅から伯備線の新見行に乗り、方谷駅で降りる。倉敷駅からの所要時間は50分だ。電車から見る風景はどんどん田舎になっていき、そして山になっていく。倉敷駅から電車に乗ったときにはそれなりにいたはずの乗客が、ふと気がつくといなくなっている。その時乗っていた車両には実に私一人しか乗っていなかった。方谷駅に降り立ち、電車が行ってしまうのを見ると、寂寥を覚えた。駅に降り立ったのは私一人だ。駅には誰もいない。見渡す限り人間がいない。当然ながら無人駅だが、かつては有人の駅であったことを思わせる設備があった。

山田方谷について

駅にあった看板を読むと、どうやらこの方谷駅は1928年に設置されたそうだ。方谷(ほうこく)というのは実は人名で、地元の名士である山田方谷に由来する。当時の駅名というものは地名に限るとされていたが、地元民の山田方谷を慕う声が大きく、「方谷」というのはこの辺の地元民が使っている山の名前であってすなわち地名である、決して人名ではござらんという屁理屈で無理やり押し通した駅名であり、方谷駅というのは日本で人名由来の最初の駅名なのだそうだ。

そこまで地元民に慕われていた山田方谷というのはどういう人物だったのか。山田方谷は幕末の備中松山藩に使えた漢学者の武士である。藩の財政を立て直すために領主勝静の全幅の信頼のもとに、質素倹約、賄賂の禁止、藩からの持ち出しのある幕府の役目から辞退といった手法で備中松山藩の財政を立て直すことに成功した。

その他にも、身分性別にかかわらず誰にでも学問を施したり、航海術を復活させて水路で物資を輸送したり、武士に農業をさせたり、武士農民混合のイギリス式軍隊を作ったりしている。

上の文はさらっとかいたが、そのどれもが当時の常識ではありえないことなのだ。

当時はそのへんの農民や子女ごときが学問を学ぶ必要はないし教えてやるつもりもないという考えが常識であった。方谷は自ら身分性別にかかわらず誰にでも学問を教えていた。

航海術もそうだ。江戸幕府は300年の長きに渡って日本を平和に治めていたが、それほど長く平和が続いたのは、国内の戦力を削ぐのに力を注いでいたからだ。例えば全国の藩に無駄な労役を強いたり、参勤交代をさせたのも、戦争ができるだけの余力を持たせないようにするためだった。特に輸送力も人工的にそいでいた。そのため、輸送は主に陸路で行われ、水路は使われなかった。このために航海術というのは江戸時代の日本では失われた技術であった。幕末から明治にかけて水路を復活させるときに、まともな航海術の知識がなかったのでそれはもう大変な試行錯誤のもとに航海術を復活させている。最初は陸地にそって移動し、嵐が来たらマストを切り落とすような無茶なことをしていた。用意に座礁するし、嵐が去った後の移動手段がなくなってしまう。

武士が農業をするというのもありえない話で反発も多く、方谷も藩内から憎まれて暗殺未遂にまで発展した。

武士農民を混合したイギリス式の軍隊も当時の常識ではありえないことで、後に長州藩の奇兵隊や長岡藩に参考にされている。

このような当時の常識に反する反発も多い様々な政策を、備中松山藩の藩主、板倉勝静の全幅の信頼のもとに実行していた。

さて幕末維新にかけて、朝廷側と幕府側で戦争が起こる。山田方谷は時代の趨勢から幕府による政治体制が終わるのは必然であると考えていたが、藩主勝静は松平定信の孫であり先祖を徳川吉宗に遡ることができる徳川家の血筋の人間であり、時代の趨勢はともかく血筋と義によって幕府側についていた。徳川慶喜と行動をともにして備中松山藩を留守にする中、朝廷側からは備中松山藩は朝敵であるとされ侵攻されることになった。

留守を守る方谷は、領民が戦火に巻き込まれることを避けるため、自らの権限で藩主勝静を勝手に隠居させ、祖父の子孫である板倉勝弼をにわかに藩主とし、朝廷側に降伏。備中松山藩を無血開城して領民を守ったのだ。このとき、勝弼は一時的な藩主であり勝静の嫡男である勝全が戻ったときは家督を譲るという起請文を勝弼に書かせていたが、やがて赦免されて戻ってきた勝静からは、「主君は簡単に改めるものではない。ましてや朝敵となった勝全に継がせるべきではない」と起請文を破り捨てられている。この藩主であるからこそ方谷のような人物を重用できたのである。

これを考えると、地元民が山田方谷を慕うのは当然の話で、文字通り命の恩人だからだ。もし山田方谷がいなかったのならば、ぜひ方谷を駅名にと強く押す地元民の大部分は死んでいたり、また行きていたとしても地元には残っていなかっただろう。

猪風来美術館への道のり

話がそれた。方谷駅には何もない。山の中に設置してある古びたコンクリートのプラットフォームだ。やや廃墟感のある薄暗い階段を降りて改札に向かう。駅員はいない。改札と駅舎らしきものはあるが誰もいない。駅の前には交通会社らしき建物があるが、あまりに古びている上に車は1台もない。駅前に喫茶店の名残のような建物はあるが、営業していたのは何十年も前の話だろう。駅舎の半分は駅資料館になっているようだが、残念ながら鍵がかかっていて入れなかった。窓から見ると本が二冊と駅の模型があるのみだった。

さて、方谷駅から猪風来美術館に移動する。駅を出て、橋を渡り、道なりに北上すると左に分岐する坂道がある。その坂道をまっすぐ進むと猪風来美術館に着く。途中、看板がいたるところにあるので迷うことはない。私はキックスクーターを持っていったが、坂道のために1/3程度しか役に立たなかった。そして、前日の雨と落ち葉で滑るのでエアタイヤが必須だ。キックスクーターを持っていった目的は帰りのダウンヒルなので、行きにそれほど役に立たないことは覚悟の上だ。道は舗装されているのが、夏はヤブ蚊が多く、冬には雪が積もるという。11月の初旬は暑くもなく寒くもなく丁度いい気候であった。東京から村上原野の弔いに来て時間と体力があるのであれば歩いていくことをおすすめする。

猪風来美術館到着

美術館に上がる最後の分岐路を登ろうとしたところで、後ろから車がやってきた。村上原野の母むらかみよしこと、縄文土器製作に入門する弟子が一人乗っていた。

猪風来美術館は廃校となった学校を利用した美術館だ。展示品のほとんどは村上原野の父猪風来の縄文土器、妻むらかみよしこの作品と、その息子である故村上原野の作品で占められる。

村上原野の作品は3歳の時に粘土に押し付けた手型足型から始まり、小学校の頃のセミの抜け殻などがある。いずれも土器や陶器である。作品はやがて出土した縄文土器の複製品になり、そしてオリジナルの造形品になっていく。村上原野の最後の作品は「渦巻く翅(つばさ)のヴィーナス」だ。

作品を見ていると、猪風来がやってきた。縄文土器について前々から思っていた疑問である、なぜ火焔土器のような複雑で実用的ではない造形をするのかという質問をしようとする私を遮り猪風来は言った。「おまえはまだ縄文の心を分かっておらん。まず作品をすべて見ろ。話は後からだ」

猪風来の作品を見ると、とにかく縄文土器で大きな作品を作ろうしているように思える。これは芸術性というより技術的な挑戦に思える。

粘土と熱変性について

粘土を加熱すると化学変化が起こり、詳細は省くが、結果として硬質化する。このとき、熱が高いほどより激しく変性する。土器の技術の歴史は、より高い熱を実現する歴史でもある。縄文土器は低温(600-900℃)で作られる。これは、縄文人が熱を実現する手段として野焼きしか使わなかったためである。より高い熱を実現するためには燃焼中に土や藁をかぶせるとか窯が必要となる。

野焼きの低い温度で実用的な土器を作るためには、適切に調合した粘土のほか乾燥、磨きなど様々な技術が必要になる。縄文土器を作る技術は失われていたが、3,40年ほどまえに猪風来が試行錯誤の末に再発見した。

大きくて複雑な造形には時間がかかる。しかし粘土は乾燥してしまうと造形ができなくなる。そのため、猪風来の大きくて複雑な造形の作品は、パーツごとに造形して組み合わせる形で作られている。あるいは造形は質素だがとにかく大きな物体になる。

猪風来によれば、縄文粘土が造形可能な期間は7日間。濡れタオルで保護にすることによりもう7日間ほど伸ばすことができるのだという。造形可能な製作期間は2週間だ。

これを考えると、追加の造形は追加のコストである。しかも造形可能な期間が限られるのであればなおさらだ。複雑な火焔土器が芸術品とか祭器などというのであればわかるが、すべて実用品であり、煮炊きに使われていた考古学的証拠が確認されている。なぜなのか。

猪風来は語り始めた。

猪風来による土器の日本単一発祥説と縄文土器の文様の理由

数万年前、海面は今より低く、日本列島は大陸と地続きであった。日本列島と大陸の間は徒歩により気軽に往来ができた。人類最古の土器は日本で発明され、世界各地に伝播した。

やがて海面上昇により、日本列島は大陸から隔絶され、往来が難しくなった。この結果、大陸で農耕技術が発展しても、日本にはなおもしばらくは縄文文化が続いた。日本は豊かな土地であり、農耕をしない狩猟採集文化では、資源を奪い合う必要もなかった。粘土もそうだ。土器に必要な粘土は火山灰からできるのだが、これは日本十どこにでもある。現に縄文時代からは対人武器は発掘されていない。対人武器は弥生時代以降から見つかっている。

縄文土器の文様に現代人の考える実用的な価値はない。しかし、縄文人には宗教的理由があった。縄文土器の底には小さな突起がついている。これは乳房型の尖底土器であり、実際乳房を表現している。そもそも縄文土器の作成者は女性である。縄文時代は母系社会であった。農耕により土地所有という概念が生じると文明は父系社会に移行するのだが、縄文人は農耕をしておらず母系社会だったのだ。

文様の意味はなにか。これは食物を煮炊きして食べるときに命に感謝するための表現である。具体的には大地から上に上がるエネルギーを表現するために下は質素に縦線になり、天から下に下るエネルギーとぶつかるところで渦を巻き、勾玉を生ずる。勾玉は胎児の形を表現している。土器のここをみろ。ここに勾玉がある。さらにこの部分の空洞も勾玉の形になっている。

土器の複数発祥説

土器は複数の地域で独立して発明されたという説もある。少なくとも、東アジア、メソポタミア、北米で独立して発明されたとされている。

文様と勾玉の意味論

縄文時代から大量に出土する勾玉の形状が何を表現しているかについては諸説ある。胎児の形を表現しているというのも説のひとつだ。。縄文土器の文様が何を意味するかについても同じだ。諸説あるが、いずれも考古学的な証拠がない。縄文人は文字を持たなかったために、その意味は失われてしまった。

猪風来の説は裏付けする証拠がない。猪風来によれば、縄文人と同じ竪穴式住居に暮らして生活すれば、体験として勾玉や文様が必要であることが実感できるということだが、無理がある。

第一、縄文人と同じ体験を現代人がすることは無理な話だ。猪風来は冬の北海道で竪穴式住居に夜寝るときの経験を語った。では猪風来は縄文人の衣服を着ていたのだろうか? 否、現代の防寒具を着ていた。工房では弟子が縄文土器を作成していた。なめらかに回る現代のろくろの上で作業をしている。そんな加工精度の高いろくろを縄文人は持っていなかった。実際には濡れた落ち葉の上で回していたようだ。粘土は乾燥を防ぐためにビニール袋にいれられている。ビニール袋などというものは縄文時代にはなかった。作成中の縄文土器は乾燥を防ぐために濡れタオルがかぶせてある。現代のきめ細かい木綿やポリエステルのタオルを縄文人は持っていなかった。

村上原野のこと

村上原野は猪風来が縄文人の心を会得するために北海道の竪穴式住居で暮らしていたときに生まれた。北海道の原野で生まれたので原野と名付けられた。芸術家の家庭に育ったためか、子供の頃の作品が残っている。最初の作品は粘土につけた手形と足形だが、小学校から高校にかけては粘土による造形作品がでてくる。村上原野本人による当時の説明文には「自家製の粘土を使って作った」と書かれているが、一般のご家庭には陶芸用の粘土はないし窯もないものだ。ましてや家が竪穴式住居となると、一体どのような学校生活を送っていたのだろう。

村上原野は高専に行き、卒業後は数年ほど雇用されて工業製品の製図などの仕事をしていたようだ。しかし、粘土をいじっている方が楽しいと父親である猪風来に師事して縄文土器芸術家となる。

猪風来「わしは最初、反対したんだ。許さんと」

無理もない。芸術家として食べていくのは難しいし、ましてや縄文土器の陶芸家として食べていくのは相当に難しいに違いない。

最初の10年は発掘された縄文土器の模倣をしている。これは修行であり、こうして基礎を理解した後に、とうとう自分の作品を作り始めた。

縄文土器の技術は猪風来が一通り再発見したが、村上原野によって考案された技術もある。製作期間の延長だ。

すでに書いたように、縄文粘土は乾燥によりすぐに造形ができなくなる。現代の便利なきめ細かい濡れタオル包んで乾燥を防いでも、せいぜい造形にあてられる製作期間は2週間だ。村上原野は性質の違う複数の粘土を使い分けることにより、製作期間を一ヶ月にまで伸ばすことに成功した。

また、村上原野独自の造形として、土器の表面から外側に向かって伸びるような造形をする縄文土器に、外に向かって伸びた後にまた内側に戻るような造形を考案した。

猪風来も今年73歳になり、そろそろ引退を考えていて、美術館の運営を引き継ぐ予定であった。

まだ、アカデミア方面から、縄文土器を制作する時の体の動きや目線などをキャプチャーして解析しようという共同研究の話が持ち上がっていた

そして、アメリカで学問や芸術、あるいは趣味として陶芸の盛んな地域があるらしく、縄文土器の技術を学びたいと言われていて、アメリカにも拠点を作る予定だった。

私生活としても実に恵まれていた。ちょうど結婚相手が見つかり、まさに同居を始める直前であった。

あらゆる方面からの追い風を受け、将来にか輝かしい展望が待ち受けている中、村上原野は自分の芸術家としての価値を証明する渾身の代表作を作ろうとしていた。そして、頑張りすぎてしまったのだ。

猪風来「原野は北海道の生まれ育ちで、寒さに強かった。あいつは工房で暖房を使わなかった。土器の乾燥を防いで制作時間を稼ぎたいという理由でだ。原野は夜に一人で作業した。夕方に起きて一晩中作業していた。そういうことを一ヶ月も続けていた」

「わしは原野がなにかいままでにないすごいものを作っているということを感じていた。自分を代表する作品を。原野が何を作っているかは知らなかった。製作中の土器は濡れタオルで保護してあるし、わざわざ製作途中のものを見ようとはしなかった。亡くなる2日前、どうだと聞いたら、「もう一息だ」という。次の日にまた聞いたら、「もう一息」だという。これはもうそろそろできるなと思い、明け方に見に行ったら、倒れていた。手にまだ竹べらを握りしめたまま」

「兆候はあったんだ。亡くなる数日前から肩がこるといっていた。しかし気が付かなかった。陶芸家というのは作業柄、肩がこるものだから、いつもの肩こりだと思っていた」

「クモ膜下出血。医者の見立てでは即死。仮に即死ではなかったとしても、意識は数秒も持たなかっただろうということだ」

「原野は台の上に立って、腕を前に突き出して作業していた。そのまま倒れた場合、自然に前に倒れるはずだ。作品を壊してしまう。原野の体は台から離れた場所にあった。発作が起きたとき、原野はとっさの判断をして、横っ飛びしたのだ。作品を守るために。原野はこの作品を世に残すことを選択したのだ」

作品は99%完成していた。おそらく最後に上の方も穴を開ける予定ではあったのだろう。また倒れたときに竹べらで荒々しくひとかきした後が残っていた。

しかし縄文土器は造形して終わりではない。その後一ヶ月以上毎日磨く作業があり、そして何より難しい野焼きが待っている。原野の最後の作品は72時間かけて焼き上げられた。普通、小さい作品は2,3時間、大きなものでも8時間で焼き上げるという。絶対に失敗が許されないこの作品は弟子を総動員して交代制で3日間かけて焼き上げたそうだ。完成品を他の作品と比べると、確かに焼きかげんにむらがなく均一な色合いになっている。造形の難しい縄文粘土で作ったとは思えないほど複雑で立体的な造形の作品だ。

倉敷に戻る

朝早くから3時頃まで話し込み、帰りは車で方谷駅まで送ってもらった。キックスクーターでダウンヒルするというのも興味深かったが、1時間に一本しかない電車に間に合いそうにないのでご厚意に甘えて送ってもらうことにした。方谷駅から電車に乗る場合、電車のドアは自動で開かない。外側についているボタンを押して開ける。そして整理券を取る。途中の無人駅で降りる場合は電車の中で運賃を支払うが、有人駅の場合は改札の窓口に整理券を持っていく。電車の外から見える景色はみるみる山間から田んぼ、そして都会になっていき、すぐに倉敷に戻ってきた。

まだ時間があるので倉敷にあるボルダリングジム、ロックスクライミングジムに行く。

倉敷市・岡山市 クライミング ボルダリング rocks CLIMBING GYM(ロックスクライミングジム)

途中、リサイクルショップがあったので立ち寄ったところ、バランスボードとキャスターボードが安く売っていたので購入した。

ロックスクライミングジムはなかなかいいジムだった。トップロープ、リード、ボルダリングができる。課題は筋肉でごまかしがきかないようにうまく作られている。店員にビレイをしてもらい久しぶりにトップロープもした。やはりロープクライミングは面白い。東京でもロープクライミングしたいのだが、ビレイが必要なためなかなか機会がない。まずビレイできるパートナーを見つけ、日程を合わせなければならない。難しい。

11月9日

だいぶ寝坊した。ホテルの朝食の時間を過ぎている。我々は空腹のままホテルをチェックアウトし、帰りの飛行機の時間まで、倉敷の美観地区を見て回ることにした。

私の美観地区に対する感想としては、建築様式の違うシャッター商店街という感じがした。多くの建物は閉じているかテナント募集中。今日は月曜日なので特に営業していない店が多い。

空腹の我々は飲食店をさんざん探し回った挙げ句、結局安い焼き肉を食べ、それでも残った時間を駅前のショッピングモールで過ごした。旅の終わりというのは不思議なものだ。こうして身は岡山にいるというのに、数時間後には東京の自宅に戻っているわけだ。

数時間後、特に何事もなく東京に帰宅した。

2020-09-17

gem installでnokogiriとrmagickが失敗する場合

なぜ失敗するかというと、nokogiriとrmagickはシステムに特定のソフトウェアやライブラリが入っていることに依存しているからだ。依存しているソフトウェアやライブラリをPATHの通った場所に用意してやらなければビルドができない。

nokogiriで問題になるのは主にlibxml2だ。nokogiriは独自のパッチをあてたlibxml2をビルドして使う。libxml2のビルドに必要になるソフトウェアとライブラリがある。

具体的な方法は公式ドキュメントに情報がある。

Installing Nokogiri - Nokogiri

特に入っていない可能性が高いのはzlibとliblzmaだ。Debian系ならば以下のようにパッケージをインストールする必要がある。


apt install build-essential patch ruby-dev zlib1g-dev liblzma-dev

rmagicはImageMagickのRuby bindingだが、システムにImageMagickがインストールされていなければならない。またインスールされているヘッダーファイルやオブジェクトファイルを発見するためにpkg-configも必要だ。

GitHub - rmagick/rmagick: Ruby bindings for ImageMagick

Debian系では以下のように依存パッケージをインストールする


apt install build-essential pkg-config libmagicwand-dev

2020-09-05

C++20の標準規格が承認された

C++20の標準規格がC++標準化委員会で承認されたそうだ。

残念ながら私の今の仕事がC++ではなくなってしまったので、C++の参考書を執筆する時間を捻出することはできないし、C++20に追加された一部の機能に懐疑的な立場であるので、喜ぶべきなのかどうかよくわからない。

一時期、C++の参考書執筆を続けるべく、C++の教育に価値を見出しそうな転職先を探したこともあったが、どうやら国内ではC++の最新規格の教育にそれほど価値がないらしく、結局今は普通のプログラマーにpivotしつつある。

普通のプログラマーはC++教育者とはだいぶ特性が異なる。C++の規格は一個の人間が全容を理解できる程度の小さな問題であり、完全に理解して解説するだけであった。しかし、現実のソフトウェアは一個の人間が理解できる規模を遥かに超えている問題であり、自分の担当の範囲外について理解しようとする無駄な努力をやめなければならない。自分が入社する前から開発されていた数千万行のコードをすべて理解するのは不毛だし、したところで仕事ができるようにはならない。使うプログラミング言語やソフトウェアも多岐にわたるため、すべてを理解するのは一個の人間の時間では足りない。普通のプログラマーは巨人の肩の上に乗っているが、その巨人について理解しようとしてはならないのだ。

C++は私のフルタイムの時間と趣味の時間をどちらも投じて全容を理解できる規模の問題だったが、今は仕事ではなくなり、また趣味も健康面を考慮して運動に切り替えた今、C++に割くための時間が足りない。C++20の参考書は暇な時間にたまに執筆しているが、おそらく完成することはないだろう。

2020-08-31

360度カメラの残念な現状

冬のスノーボードのために動画撮影用のカメラを買おうと思っている。今の所、GoProの次のモデルが発表されたら買うのを検討しようかと思っているのだが、360度カメラという選択肢も出てきた。しかし調べたところ、360度カメラの現状はあまりよろしくない。

360度カメラではカメラを中心に全周囲を撮影できる。これによって追い撮りするときに撮影対象を収めそこねたという問題を回避できるし、自分も周囲も同時に撮影できる。私の目的は思い出を記録しておくことだから、360度カメラはとてもいい選択肢のように思える。

360度カメラは2つ以上のレンズを使って撮影した複数の映像をつなぎ合わせることで実現されている。一般的な製品では半球レンズを2つ使って2つの動画を撮影してつなぎ合わせている。

撮影した生の映像は、半球レンズによって著しく歪んだ2つの動画にすぎない。このままでは見るに耐えないので、視点を固定し、その視点に合わせた現実的な狭い視野を模した動画の一部のみを再生することになる。そのための処理として、製品ごとに異なる独自のプロプライエタリなソフトウェアが必要になる。

まずstitchingを行う。撮影した複数の動画は境目となる部分を単に重ねただけでは継ぎ目が明らかになってしまう。撮影部分がオーバーラップしたり、撮影方向の違いによって当たる光の関係で映像の色温度が変わってくる。これをごまかすために、オーバーラップ部分を認識したり、継ぎ目をぼかしたり、色温度を調整したりといった処理が必要になる。複数の独立したカメラを使って手動で360度動画を作るならこれはすべて手動でやらなければならない。360度カメラのようにあらかじめカメラ特性が分かっているのであれば自動化も可能になる。そのためのソフトウェアはカメラベンダーが提供するプロプライエタリなソフトウェアとなる。GoPro MAXではstitchingはカメラ内で撮影時に行われる。

次にprojectionが必要になる。我々の視野は360度ではない。そのため視聴環境に合わせて動画を変形させなければならない。視聴環境が平面ディスプレイせよ、VRディスプレイにせよ、必要だ。この処理も事前にカメラ特性がわかっていれば自動化できるが、そのためのソフトウェアもカメラベンダーが提供するプロプライエタリなものになる。

360度動画に必要なものは規格化であるように思われる。stitchingはカメラ内で行えるが、projectionは処理量的にカメラ内ではやりにくい。その方法もまだ発展段階にあり混沌としている。projectionを規格化することによってカメラベンダーごとのプロプライエタリなソフトウェアの必要をなくしてほしい。

なぜこれを問題視しているかと言うと、プロプライエタリなソフトウェアが10年後に動作する保証はどこにもないからだ。しかも360度動画のprojection処理はGPUを使うのでなおさらだ。

2020-08-15

LinuxカーネルにおけるGPLコンドーム問題への対処パッチ

最近、Linuxカーネルで話題になっていることに、GPLコンドーム問題がある。

Kernel Developers Work To Block NVIDIA "GPL Condom" Effort Around New NetGPU Code - Phoronix

発端はNetGPUと呼ばれる機能をLinuxカーネルへ追加するパッチだ。これはNICとGPUの間のデータ転送にDMA zero-copyにしてNICとGPUが直接やり取りできるようにしつつ、プロトコル処理自体はCPUに処理させるという機能で、GPGPUがますます汎用化してくるなかでGPUから直接ネットワーク越しにデータを転送する事ができるようになる。

ところが、NetGPUをNVIDIAドライバーに対応させるパッチとやら出てきて物議を醸している。NVIDIAのドライバーはプロプライエタリであり、LinuxカーネルのGPLシンボルを使うことができない。そこでLinuxカーネルとNVIDIAのプロプライエタリドライバーをつなぐ目的のためだけの薄いshimコードをGPLと称する手口が流行っている。これがGPLコンドームと呼ばれる問題だ。NetGPUがプロプライエタリなNVIDIAだけを利するものであれば、そもそもLinux上流に取り入れる意味がない。

その流れを受けて、GPLコンドーム問題に対処するパッチが出てきた。

Linux 5.9 Brings Safeguard Following NVIDIA's Recent "GPL Condom" Incident - Phoronix

これはGPLを称しながらプロプライエタリなシンボルを使うカーネルモジュールに対してもTAINT_PROPRIETARY_MODULE taintを付加するものだ。

2020-08-05

GDBがeBPFのデバッグをサポートした

GDBがeBPFのデバッグをサポートした。

GNU Debugger Adding eBPF Debugging Support - Phoronix

eBPFというのはLinuxカーネル内の仮想マシンだ。

もともと、BPF(Barkley Packet Filter)という仮想マシンがあった。これはネットワークのパケットフィルタリングをするための仮想マシンで、レジスターベースのRISCプロセッサーを模した命令セットになっている。

カーネル内で安全にユーザーコードを実行するというのは需要があるので、BPFをより汎用的に使いたいという声は多かったのだが、何分BPFは設計が古い。レジスタは2個で32bit、命令セットはatomic compare exchangeのようなモダンなプロセッサーに搭載されている命令がない。

そのためeBPF(extended BPF)が設計された。レジスタは10個で64bit、命令セットもモダンなプロセッサーにマッピングできるように見直された。

2020-08-02

キャスターボード

かねてから気になっていたキャスターボードを買った。今回買ったのはRipStik Air Proだ。

キャスターボードは一見するとスケートボードに似ているが、スケートボードではない。スケートボードは板の下に二輪ずつのウィールが前後に付いているものをいう。キャスターボードは、前後に1輪づつしかついていない。しかもウィールはキャスターにつながっていて、回転する。このキャスターは水平に対して30度ほど傾けて取り付けてある。

キャスターボードの元祖は韓国で発売されたEssBoardであるといわれている。その後、アメリカでRazorがRipStikという製品を出してから有名になった。オリジナルのRipStikは板が2枚あり、その間をトーションバーでつないでいる。その後、一枚の板でトーションもきく製品が発売された。今回買ったRipStik Air Proは1枚板の製品だ。

さっそく乗ってみたが、意外と簡単だった。スノーボードの経験が効いているものと見える。筋肉の疲労具合もスノーボードと似ている。スノーボードのオフシーズンのトレーニングに丁度いい。

キャスターボードはトーションをきかせつつ前後の足を互い違いに動かすことで進むことができる。また、腰のツイスト運動で進むこともできる。どちらもひねり運動の一部を前進運動に変換しているようで、スケートボードのキックターンと同じだ。ただ、ひねり運動から前進運動への変換には極めて低い上限があるらしく、ある速度を超えるとひねり運動が過剰になるだけで前進速度は少しも上がらなくなる。

運動負荷も高い。私は片足スクワットができる上に9kmのジョギングもできるし毎日6kmほどキックスクーターで移動している。それでもキャスターボードでは数百メートルも進むと後ろ足がパンプする。キャスターボードを始めてから一ヶ月ほどすると、筋持久力は上がってきたのだが、今度はヒザに違和感が出てきた。痛みと言うほどではないがかゆみがある。そのためヒザの調子を見つつトレーニングしている。できれば週に2回はトレーニングしたいのだが、ヒザの回復を待つために週に1回ぐらいしかできていない。

キャスターボードの構造上、スイッチができない。動画ではウイリーやオーリー、360といったトリックができるようだが、とてもできるようには思えない。

最近は板から降りずにレギュラーとグーフィーの両方で1km進むことができるようになった。

キャスターボードは後輪ウィールの消耗が激しい。RipStick Air Proには76mmのウィールがついているようで、インラインスケート用のウィールと同じものなので硬度の高いウィールを注文した。ベアリングも安いものを注文したが、いずれスケートボード用のオイルベアリングを試してみてもいいかも知れない。

2020-07-17

GitHubのArctic Vault Contributerになった

以下のような企画がある。

GitHub Archive Program | The GitHub Archive Program will safely story every public GitHub repo for 1,000 years in the Arctic World Archive in Svalbard, Norway.

1000年後に情報を残すために、GitHubの一部の注目を集めたパブリックレポジトリをフィルムに転写したものが北極海の地下シェルターのなかに収められた。その中に私の貢献したレポジトリーも含まれていた。

まず私が書いた参考書のC++11/14コア言語の原稿だ。

EzoeRyou/cpp-book: C++11 textbook

これは主に私が書き、多数の人間がPRで修正をした参考書の原稿だ。

つぎに、CPUを使ってラジオを鳴らそうというコードだ。

fulldecent/system-bus-radio: Transmits AM radio on computers without radio transmitting hardware.

sleepを挟んで1秒間に1000回CPUに負荷をかけると、周囲に1000Hzで電磁波ノイズが飛ぶ。これはAMラジオで拾えるぐらいのノイズになる。つまりCPUを使って特定の周波数のノイズを表現でき、周波数を適切に選べば音階も表現できるので、音楽を発信できるのではという雑な考えで書かれたコードが、実際に動いてしまった。私はコードをC++11に移植した。またスレッドも使うようにしてよりCPUに負荷をかけ、ノイズも強くした。

最後に私も貢献したことになっているのだが、ちょっとよく覚えていないのがこれだ。

cplusplus/draft: C++ standards drafts

これはC++標準規格のソースコードだ。おそらく私も何らかの修正をしてPRがマージされたから参照されているのだと思うが、よく覚えていない。調べれば分かると思うのだが面倒なので調べていない。

2020-07-05

スノーボード用の別荘を検討している

COVID-19によりリモートワークが長引いている。ここまでリモートワークが長引くのであれば、いっそのこと冬はスキー場近くに別荘を用意して滑りながら仕事をするのはどうか。これを真面目に検討してみた。

別荘を手に入れるためには購入するか賃貸しなければならない。購入するのは簡単だ。バブル期に立てたリゾートマンションが腐るほどある。現金が数百万もあればよい。中には取引額が負数の不動産さえある始末。問題は維持費だ。固定資産税がかかるし管理費、修繕積立金もかかる。そして日本では不動産を放棄することができないので、バブル崩壊後のリゾートマンションはババ抜きとなっている。

引退後にその地方に移住するならば購入はありだが、運動強度の高いスノーボードを老後も続けられるかどうかはわからない。

賃貸はどうかというと、これがまたスキー場近くの不動産の購入に価値がないと思わせるほど賃料が安い。月3万も出せばワンルームから2DKぐらいの部屋が借りられてしまう。問題は冬の間4ヶ月だけ借りて最低限住めるだけの環境を整え、シーズンが終わったら撤退する手間は面倒だ。通年で借りれば毎年賃貸契約と解約をする手間は省けるが、特に登山趣味もないので夏の間の価値はほとんどない。

手間もさることながら、場所の問題もある。

越後湯沢駅の徒歩4分のところに、月1.6万円のワンルームと3.2万円の少し広いワンルームがある。駅からバスで各スキー場に行くことができる。東京-越後湯沢が2時間、越後湯沢駅から各スキー場まで20-40分といったところだ。月1.6万円は極めて安く、通年借りたとしてもそれほどの負担ではない。問題は、越後湯沢周辺のスキー場は雪質はそれほどでもないということだ。東京からの交通の便がよいために栄えている場所だ。駅前の土地勘はそれほどないが、車なしで数ヶ月滞在することぐらいはできるだろう。

白馬駅から800mのところに月4.8万円の2DKがある。白馬村は前シーズンに2週間滞在したことがあり土地勘がある。白馬駅からバスや電車で各スキー場に行くことができる。スキー場までは1時間弱といったところだろう。付近には温泉もスーパーもある上、好日山荘に小さなクライミングウォールがある。東京からバスと電車の連絡にもよるが4時間ぐらいだ。

妙高市の新井駅の近くに、月3万ぐらいで1Kから2DKぐらいの賃貸がある。問題は土地勘が一切ない。地図を見る限り駅前は車なしでも数ヶ月滞在できそうな気はする。近所にボルダリングジムがある上、トップロープまでできる場所もあるようだ。問題はスキー場なのだが、新井駅から電車で26分かけて妙高高原駅に行き、そこからバスで赤倉温泉、赤倉観光、池の平、杉ノ原といった各スキー場に移動するか、関山駅に行ってバスでロッテアライリゾートと関山温泉スキー場に行くことができるようだ。新井駅からスキー場まで1時間以上かかるだろう。東京からは4,5時間ぐらいだ。

賃貸を借りるならいい加減に不動産屋に連絡を入れないといけないが、何分遠方の物件なので手間がかかるし踏ん切りがつかない。

2020-06-30

職質裁判、上告不受理で終了

職質裁判は上告不受理で終了した。

calling-110-is-suspicious/20200626_zyoukoku_huzyuri.pdf at master · EzoeRyou/calling-110-is-suspicious

経緯はこうだ。3年前にひどい職務質問を受けた。

警察官に職務質問をされた話

警察官職務執行法に規定されている通り、職務質問をするためには職務質問を受ける人物について犯罪を犯した、あるいはこれから犯罪を侵すと疑うに足る相当な理由が必要だ。それに職務質問で規定されているのは質問であって、開口一番にリュックの中身を見せろと発言するのはもはや質問ではない。そして警察官2人がかりで路上に羽交い締めにされたり、多数の警察官によって私有地の駐車場に監禁され、何の法的根拠もない手荷物検査に応じるまで解放しない。これは説得でありお願いであるので法的根拠は必要ないと2時間拘束されたわけだ。職務質問において私が警察官職務執行法に規定する相当な理由について質問したところ、警察官が答えたのは、「帽子を目深にかぶっていた」、「うつむいて下を向いて歩いていた」ということだけで、特に「うつむいて下を向いて歩いている」者は「薬物中毒者である可能性が高い」と言われた。

これに対して東京都を相手に裁判をしていたのだが、一審では不審事由がなくても声をかけることは違法ではなく、110番通報を要請することは不審事由に当たるのでその後の職務質問は正当であるという判決が出された。裁判では、東京都は本当に謎の主張をしてきだ。私が手を小刻みに震わせているという職質当時は一切指摘されなかった主張をしたり、警察はパトカーから私とすれ違ったが、そのとき私は顔を伏せてパトカーから逃げ去ったという主張だ。私には手を震わせる持病はないし、ましてや東京都の主張する私とパトカーがすれ違いざまに走り去ったという地点から10m先の自動販売機で、私はのんびりと飲み物を購入しているわけだ。私は走っていないし、走り去ったとしたらなぜ10m先の自動販売機でのんびり飲み物を購入しているというのか。そして目の前の警察官があまりにも法律を無視しているので110番通報を要請したところ、目の前の警察官は110番通報を阻止したのだ。そして裁判では110番通報の要請は不審事由に当たるとされた。

二審では110番通報の要請は怪しいという部分は削られた。しかし結論は変わらず、不審事由がないにもかかわらず職務質問は妥当であるという結論は変わらなかった。

判決で参照されている判例は、車を運転中に物損事故を起こした上で呼気検査を拒否したとか、検問での呼気検査に引っかかったが検問が違法なので違法な証拠収集であるという、もともと無理筋の裁判で、この判例を歩道を歩いている何の違法行為も事前に認められない人間を相手に適用すべきかということで上告したが、結果は上告不受理であった。

この結果から何の教訓を引き出せばいいのかわからない。一番の敗因は110番通報を妨害され失敗したことであるように思われる。110番通報の通話記録は確実に残り強い証拠として使えるので、今回東京都が主張してきた様々な嘘が嘘であるという証拠になる。当時私は録音録画する装置を持ち合わせておらず、またプライバシーを優先して携帯電話も持たない主義なのでその場で110番通報できなかったのだ。

これからは自衛のために常日頃からボディカメラを装着して持ち歩くべきだろう。常時録音録画しておき記録に残すのだ。

警察の偽証から自衛せねばならぬとは嫌な世の中になったものだ。

2020-06-21

バックトゥザフューチャーのタイムライン

話題になっていたので映画バックトゥザフューチャーのタイムラインについてまとめてみた。タイムトラベルが行われるたびに新しいタイムラインが生成される。これは映画三部作だけを参考にしており、テレビ放送アニメ、コミック・ブック、小説、ビデオゲームについては考慮していない。

T0: タイムトラベルの発生しないオリジナルのタイムライン。アインシュタインは1分後にタイムトラベルしない。地名は二本松モール。ドクはリビヤ人テロリストによって射殺される。マーティの父親は弱気でビフにゆすられている。

T1: アインシュタインが1分後にタイムトラベルする。オリジナルのT0とほとんど変化はないと思われる。

T2: マーティが1985年から1955年にタイムトラベル。木を一本車で引き倒したために地名が孤独松モールに変わる。ドクは防弾チョッキを着ていたので生存。父ジョージが自信家になりビフは真面目になる。マーティのその後の消息は不明。

T3: マーティが1955年から1985年にタイムトラベル。マーティはジェニファーとドライブデート中に腰抜け(Chiken)と煽られ交通事故を起こし障害者になる。マーティの息子がそそのかされて犯罪を起こし、マクフライ家は崩壊。

Ta: ドクがa回のタイムトラベルをしたことによりn個の世界線が発生する。aの数は不明。デロリアンにMr. Fusionが搭載され、家庭ごみを燃料に駆動するようになる。空も飛べるようになった。

T4: ドク、マーティ、ジェニファーが2015年にタイムトラベル。マーティの息子に将来降りかかる危難をなかったことにする。その後のドクとマーティとジェニファーの消息は不明。

T5: ビフが2015年から1955年にタイムトラベル。2015年に入手したスポーツ年鑑を1955年に使い博打で大儲けした結果、ビフが大金持ちになる。周辺の治安は悪化。マクフライ家は崩壊、父ジョージはビフに殺され、母ロレインはビフと再婚。ドクは精神病院に入院。没案では1985年以降にロレインはビフを射殺。

T6: ドク、マーティ、ジェニファーが2015年から1985年にタイムトラベル。T5の世界線を観測する。

Tb?: ドクがビルの屋上に追い詰められたマーティを助けるタイミングの都合が良すぎるので、ドクは何度かタイムトラベルした可能性がある。

T7: 1955年に戻りビフからスポーツ年鑑を奪う。T3の世界線に戻る。

Tc?: ドクがマーティをトンネルで助けるタイミングの都合が良すぎるので、ドクは何度かタイムトラベルした可能性がある。

T8: ドクの乗るデロリアンが雷に撃たれて1955年から1885年にタイムトラベル。マーティは郵便配達人から100年前の手紙を受け取る。ドクは手紙を書いて程なくしてビフの先祖であるビュフォード・タネンに射殺される。

T9: マーティが1955年から1885年にタイムトラベル。クララが生存。マーティがビュフォード・タネンに射殺される。

T10: マーティが1885年から1955年にタイムトラベル。ショナシュ峡谷がイーストウッド峡谷に変わる。マーティは腰抜け(chiken)と煽られても交通事故を起こさない。

Td: ドクがd回のタイムトラベル。

2020-06-13

キックスクーター

キックスクーターに乗り始めて早2年、いろいろと分かってきたので書き出しておく。

最初に買ったキックスクーターは1万円ほどの安物で、これは悪くはなかったが、もう少しいいものがほしいので人に売り払った。

次に買ったのはMicro MobilityのCity BMW Scooterだ。これはBMWとの公式コラボ製品で、日本で正規の購入代理店がいて手軽に買える中では最も高い製品だ。

- micro-mobility.com

しばらく使った感想としては、ソリッドタイヤでは快適に走れる道がかなり限られるということだ。大通りの道の舗装はかなり荒いアスファルトになっているので快適ではない。大通りからそれた路地がおすすめだ。またどうもこの製品はフットブレーキの作りがあまりよくない。すぐに壊れてしまった。

COVID-19の影響もあって電車に乗りたくないので、エアタイヤのキックスクーターを買ってみることにした。前輪が230mm、後輪が205mmのエアタイヤになっている。

FR230P | Frenzy Scooters

しかし、これがまたかなりひどい欠陥品だった。届いた製品の後輪のタイヤが分厚すぎてフレームに干渉してしまう。販売店に相談して純正品の交換パーツを送ってもらったが、これまた同じ欠陥を抱えている。返品を考えたが、物自体はそれほど悪くはないので、アマゾンで中華製の8インチのエアタイヤを買ってみた。これがなかなか悪くなく細めにできていて70PSIも入る。これでようやく快適になった。これで荒いアスファルトも石畳も怖くない。ただ、ソリッドタイヤに比べてほんのわずかに速度で劣る気がする。ベアリングの質の問題ではないはずなので、運動エネルギーの一部が減衰性のある素材のせいで熱に変わっているせいだろうか。

結論から言うと、おそらく前輪後輪とも205mmのキックスクーターでよかったのではないかと思う。というのも230mmエアタイヤというのは珍しすぎて交換品がない。タイヤチューブはあるのだが、ベアリングホイールとタイヤの交換品がみあたらない。205mmはチューブ、ベアリングホイール、タイヤとも豊富に互換品が存在する。

2020-06-01

パブリックドメインの漫画が出てくるのは2050年代から、アニメは2030年代から

Redditでパブリックドメインな漫画は存在するのかと質問されていたので考えてみた。

Are any manga in the PUBLIC DOMAIN? : japan

2018年に改正された日本の著作権法では、個人の著作権の保護期間は死後70年を原則として、映画、無名、周知されていない著作物は公開から70年となっている。改正時にすでに著作権条保護されていない作品について保護期間が延長されることはないので、1967年に著作者の死亡した作品の著作権の保護期間は満了しているが、1968年に著作者の死亡した作品の著作権は2038年まで存続する。

それを踏まえて日本の漫画の歴史を紐解くと、1930年代には、現代風の漫画が公開されている。このときの漫画家達は1970年から1980年頃まで生きているので、著作権の保護期間が満了してパブリックドメイン漫画が出てくるのは、1950年代以降ということになる。

もちろん例外はある、1967年までに死んだ漫画家の著作物はすでにパブリックドメインになっている。ただし、それほど多くはないだろう。

アニメは法律上映画になるので、アニメの著作権は漫画より早く消失する。日本のアニメは1960年代から発表されているので、2030年代にはパブリックドメインのアニメが出てくることになる。

判例を考えると、映像表現をともなうビデオゲームは映画の著作物になる。任天堂のファミコンは1983年に販売されている。したがって2054年以降から、パブリックドメインのファミコンのゲームが出てくることになる。

2020-05-03

マッスルアップができない

クライミングジムがのきなみ営業自粛してしまってからしばらくたつ。その間に筋力だけでも落とさないようにと公園の鉄棒でトレーニングをしているのだが、クライミングとは違う身体の動きを要求される。

最初はなかなかできなかったうんていだが、最近はラクラクとこなせるようになった。これは筋力が発達したのではなく、効率的な身体の動かし方を学んだのだろう。垂直な鉄の棒を腕だけで登ることもできるようになったし、落差50cmぐらいの棒から棒に飛び移ることもできるようになった。

クライマーからすると、鉄棒はガバすぎて指に対する負荷が足りなすぎるので、ロックリングスを買ってみた。ふしぎなことに単に鉄棒で懸垂するより指3本を第一関節だけかけるロックリングスのほうが懸垂がやりやすい気がする。クライミングはするが鉄棒での懸垂はほとんどしてこなかったことが影響しているのだろう。またローリーバーも買った。クライミングジムでたまに触るのとちがって、自分で所有して本格的に30分ほど取り組むと、だいぶ手首に負担がかかることが分かった。ローリーバーはそれほど長時間するものではない。

現在の目標は鉄棒でマッスルアップができるようになることだ。マッスルアップをするための筋力はすでに十分に備わっているはずなのだが、マッスルアップができない。マッスルアップのうち、プルアップはできるが、そこから身体を持ち上げることができない。なので最近はディップスのトレーニングをしている。クライミングジムが再開したらマントル返しやプッシュに向上につながることを期待している。

ところで、電車に乗ることを避けるためにエアタイヤのキックスクーターを新しく購入した。FrenzyのFR230で、前輪が230mm、後輪が205mm。両方共エアタイヤだ。届いた当初、常にブレーキがかかったような感覚を覚えると思ったら、後輪のタイヤがフレームに干渉していた。初期不良を訴えて交換してもらったのだが、交換してから20日で今度は後輪がパンクした。どうもこの製品、製造上の欠陥がある気がしてならない。タイヤというのは荷重するとわずかにたわんで幅が広がる。Frenzyの後輪のフレーム部分の幅が狭すぎ、たわんだ際に干渉する問題があるのではないかと思っている。

とりあえず古いキックスクーターから205mmのソリッドタイヤを移植したが、一度だけ自転車屋にタイヤをパンク修理で持ち込んで見ようと思う。しかし、新品が20日でパンクした以上、あまり期待はしていないのだが。

2020-04-17

検出不可能なゲームのチートが発表、今後のオンラインゲームのデザインはこのチートを前提に設計しなければならない

PCILeechというソフトウェアスタックがある。

ufrisk/pcileech: Direct Memory Access (DMA) Attack Software

これはPICeデバイスを使ってターゲットコンピューターのメモリをDMAで読み取るためのPCIeデバイスのFPGAの実装とその操作のための一連のソフトウェア群だ。

原理は簡単だ。ターゲットコンピューターのPCIeスロットにつないだPCIeデバイスからDMAをするだけ。これによりターゲットコンピューターのメモリ領域を読み取ることができる上、ターゲットコンピューターからは検出不可能だ。なぜならばDMAはCPUを介さずに行われる上、ターゲットコンピューターにカーネルスペース/ユーザースペースともに追加のコード実行を必要としないからだ。

PCILeechを作って作られたゲームのチートに、CSL:GOのチートがある。これはマップ上のどこにプレイヤーがいるかを表示するチートだ。

pcileech-webradar/readme.md at master · EngineOwningSoftware/pcileech-webradar

原理上、このチートはターゲットコンピューターからは検出不可能だ。したがっていかなるDRMであろうとも役に立たない。難読化をして多少チートの開発を嫌がらせすることはできるかもしれないが、所詮その程度だ。もはやゲームにおいてメモリは常に読まれるものと考えなければならない。

このチートに抗うのは無意味だ。したがってこれからのオンラインゲームはローカル環境でのメモリが読まれることを前提に設計しなければならない。CS:GOのようなオンラインFPSゲームでは、全プレイヤーの位置は公開すべきだろう。すなわちこのようなチートの意味をなくすのだ。オンラインポーカーのようなゲームでは、ローカルに秘密情報を保持しない実装にしなければならない。秘密情報については中央の権威サーバーのみが処理するか、メンタルポーカーのアルゴリズムを使う。オンラインFPSも中央の権威サーバーによる実装もできるが、それはGoogle Stadiaのような入力をサーバーに送信して映像をストリーミング再生するだけのような実装になるだろう。

この仕組みを使ってメモリに書き込む場合は検出可能だろう。というのも連続していない任意箇所のメモリに対してアトミックに書き込むことはできないので、ゲーム状態を重複して複数のメモリ箇所に保持したり常時チェックサム計算などの対策で、メモリ改変を検出できるはずだ。

また、自分のプログラムが全メモリアクセスを専有している場合は、メモリ帯域を常時使い切ることにより、メモリ帯域に変化が生じればそれはDMAアクセスが行われたと考えていいだろう。問題はPCILeech以外の各種デバイスかもしれず、またIntel MEやAMD PSPのような邪悪で不自由なバイナリブロブのファームウェアによるものかもしれないので、切り分けができない。そして全メモリアクセスを専有する状態ではもはやPCゲームは実装できない。

世の中から無意味で邪悪で人道上の罪であるDRMは滅ぼさなければならない。

2020-04-16

Error handling in Erlang

Last time, I wrote about how to write a hello world HTTP server by using Erlang, Cowboy and Rebar3.

Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

Today, I'm going to write about the error handling in Erlang.

The error handling in Erlang is easy if we can ignore the error. That is, we don't expect the error. In the event of unlikely failure, we immediately abandon any computation we were doing and start over. The OTP and other famous frameworks were written by following Erlang culture of error handling so it will handle it well. If, on the ohter hand, the errors are expected to happen, so we have to explicitly deal with it. Erlang is suddenly reared its ugly head.

How a function notify it's caller the failure? In other languages, like Haskell, there is a Maybe type which may or may not contains the value. Erlang is not staticaly strong typed language so the Erlang version of the Maybe is tagged tuple. We return ok or {ok, State} upon success and we return any other value otherwise. It may be {error, Reason}, empty list [], or simply an atom like error, false, undefined whatever.

The user of such functions must match the returned value with ok tagged tuple,

do_something( State ) ->
    {ok, State_1} = f( State ),
    do_normal_things.

If the function f return anything other than {ok, any()}, match failed and throw an exception of error:{badmatch, V}. So hopefully, the higher framework catch these exceptions and restart the process.

But what if the caller want to deal with the error? We have to use the patter match for the conditional execution. It can be done by case expression or function.

case expression:

do_something( State ) ->
    case f( State ) of
        { ok, State_1 } -> do_normal_things ;
        { error, Reason } -> do_error_handling
    end.

function :

do_something( State ) ->
    do_something_1( f( State ) ) .

do_something_1( { ok, State } ) -> do_normal_things ;
do_something_1( {error, Reason} ) -> do_error_handling .

Whichever you use, it became quite verbose and boilar-plate.

Erlang has exception like many other langauges. But I feel some oddities on Erlang's exception and that is the concept of class.

The Erlang has three class of exception: error, exit, and throw. These are thrown by calling function error/1,2, exit/1, and throw/1 respectively.

If you don't care about exception, you need to do nothing. But if you care, that is, you want to run some code on the condition of exception, things get verbose.

Let's suppose that previous function f/1 return { ok, State } on success, but throw some exceptions otherwise and you want to deal with it because you expect it to happen. You can use try expression or catch expression

try expression is strightforward, if you ignore the awkward Erlang grammer that is.

try Exprs
    catch Class1:Pattern1 -> Body1 ;
    catch Class2:Pattern2 -> Body2
end

The class is either error, exit, or throw, pattern may vary. If you were to catch the exception thrown by error class's badmatch(1 = 2), it looks like this.

try 1 = 2
    catch error:{ badmatch, V } -> its_bad_man
end

Now, how to do_normal_thing and do_error_handling depending on the presense of exception? try expression can have of section and it will be evaluated only on no exception in Exprs.

try f( State ) of
    { ok, State_1 } -> do_normal_thing ;
catch
    throw:something_went_bad -> do_error_handling
end

Now how to deal with the situation where the error will be reported in either by value or exception? Use try expression's of section to pattern match the error value.

try f( State ) of
    { ok, State_1 } -> do_normal_thing ;
    { error, Reason } -> do_error_handling
catch
    throw:something_went_bad -> do_error_handling
end

There is another way to deal with the exception. The catch expression.

catch Exprs

catch expression evaluate Exprs and return its value on no exception. In case of exception, the value will be either

For exceptions of class error, that is, run-time errors, {'EXIT',{Reason,Stack}} is returned.

For exceptions of class exit, that is, the code called exit(Term), {'EXIT',Term} is returned.

For exceptions of class throw, that is the code called throw(Term), Term is returned.

Erlang -- Expressions

If it's by throw({error, Reason}), the code will be clean.

case catch Exprs of
    { ok, Value } -> do_normal_thing ;
    { error, Reason } -> do_error_handling
end

But if it's error class, the code is too ulgy to read.

case catch 1 = 2 of
    { 'EXIT', { {badmatch, _} }, _ } -> do_error_handling
end

Perhaps, error and exit class were not meant to be handled by catch expression, but some library use these even for the predictable situations. like list_to_integer, binary_to_integer. My guess is to keep the backward compatibility.

Putting it all togather, it's very verbose to handle errors in Erlang.

Let's quickly borrow a code from the hello world HTTP server I explained in the previous article. Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

Instead of returning the hello world, we're going to return the sum of two query parameter a, b.

$ curl "http://localhost:8080/?a=1&b=2"
3
$ curl "http://localhost:8080/?a=1&b=-100"
-99

All we need to do is modify the cowboy_handler. The simplest code that assume no error will be like this.

init( Req, State ) ->
    P = cowboy_req:parse_qs(Req),
    { _, A } = lists:keyfind(<<"a">>, 1, P ),
    { _, B } = lists:keyfind(<<"b">>, 1, P ),
    Sum = integer_to_binary( binary_to_integer(A) + binary_to_integer(B) ),
    Req_1 = cowboy_req:reply( 200,
        #{<<"content-type">> => <<"text/plain">>},
        Sum, Req ),
    {ok, Req_1, State ).

Well, it's not bad. But I want to deal the the error.

Suppose, the users forget the query parameters.


$ curl "http://localhost:8080/"
$ curl "http://localhost:8080/?a=1"
$ curl "http://localhost:8080/?b=1"

If this happend, our code failed the pattern match because lists:keyfind returns false.


{ _, A } = false,

In such cases, I want to reply with the helpful error messages like this.


$ curl "http://localhost:8080/"
Error: missing query parameter a, b.
$ curl "http://localhost:8080/?a=1"
Error: missing query parameter b.
$ curl "http://localhost:8080/?b=1"
Error: missing query parameter a.

We can do condional branching with either case expression or function pattern match.

Another type of error is although the query paramters are present, it has a string that cannot be parsed as an integer.


$ curl "http://localhost:8080/?a=abc&b=123"

I would like to reply with helpful error messages in this case too.

After consdering the various code, I come up with this code. It's too verbose and ugly but I think alternatives are worse.

init( Req, State ) ->
    P = cowboy_req:parse_qs(Req),
    A = lists:keyfind( <<"a">>, 1, P ),
    B = lists:keyfind( <<"b">, 1, P ),
    { Http_status_code, Answer } = process( A, B ),

    Req_1 = cowboy_req:reply( Http_status_code,
        #{&lt;&lt;"content-type"&gt;&gt; =&gt; &lt;&lt;"text/plain"&gt;&gt;},
        Answer, Req ),
    { ok, Req_1, State }.

process/2 is set of function that ultimately returns { integer(), iodata() }. Here is the verbose code.

%% for missing query parameters.
process( false, false )     -> { 400, <<"Error: missing query parameter a, b.\n">> } ;
process( false, _ )         -> { 400, <<"Error: missing query parameter a.\n">> } ;
process( _, false )         -> { 400, <<"Error: missing query parameter b.\n">> } ;
%% for invalid query parameters
process( badarg, bardarg)   -> { 400, <<"Error: invalid query parameter a, b.\n">> } ;
process( badarg, _ )        -> { 400, <<"Error: invalid query parameter a.\n">> } ;
process( _, bardarg)        -> { 400, <<"Error: invalid query parameter b.\n">> } ;
% lists:keyfind succeeded.
process( { _, A }, { _, B } ) ->
    process(
        try binary_to_integer( A ) catch error:badarg -> badarg end,
        try binary_to_integer( B ) catch error:badarg -> badarg end
    ) ;
% no invalid query parameter. return the result.
process( A, B ) ->
    { 200, { integer_to_binary( A + B ), <<"\n">> } } .

The -spec attribute for this process/2 is abomination.

-spec process(
    { bitstring(), bitstring() } | false | badarg | integer(),
    { bitstring(), bitstring() } | false | badarg | integer()
)  -> { integer(), iodata() }.

Well, at least, I understand the error handling of Erlang.

2020-04-13

Erlang, Cowboy, Rebar3によるHello World HTTPサーバーのチュートリアル

本記事では、Erlang, Cowboy, Rebar3によるHello worldを出力するHTTPサーバーの実装方法を解説する。

目的は、このプログラムを実行中に、以下のような挙動になることだ。

$ curl "htttp://localhost:8080/"
hello,world

ErlangもCowboyもRebar3も、情報が極めて少ない。しかも公式ドキュメントすら間違っている。公式ドキュメントすら間違っているのには理由があり、実際の実装とドキュメントに差がでているのだ。Erlangは変化の少ない言語ではあるが、それでもOTP17からmapが追加されたりと言語的に少し変わっているし、mapの追加により、cowboyも以前ならproplistsを使っていた部分でmapを使うようになり、しかも2.0でAPIかなり破壊的な変更が入り、2.5からはモジュールの構成も少し変わってしまった。Rebar3は本当にひどい。名前が示すように、すでに破壊的な変更を2回経ている。そして技術的負債の塊だ。

この記事で解説する程度の知識を得るのに私は公式ドキュメントと何ヶ月も格闘するはめになった。公式ドキュメントですらこうなのだから、非公式なドキュメントは本当に参考にならない。ここに書いてあることは2020年の時点では正しいが、来年はわからない。

準備

Erlang実装とRebar3が必要だ。CowboyについてはRebar3がダウンロードしてくれるので考えなくてよい。

Debian系のディストロでErlangをインストールする。

$ apt install erlang

GNU/Linuxでrebar3をインストールする最も信頼できる方法は、自前でビルドすることだろう。

$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap

これで"rebar3"というファイルができるので、このファイルをPATHの通ったディレクトリにコピーするかシンボリックリンクをはればよい。

ln -s rebar3 /usr/local/bin

これで準備が完了した。

プロジェクト作成

まずrebar3を使ってプロジェクトを作成する。名前を"hello_server"としよう。

$ rebar3 new release hello_server
$ cd hello_server

このコマンドで"hello_server"というディレクトリが作成される。その中にはテンプレート生成されたファイルがいくつかある。重要なものだけ説明する。

"hello_server/rebar.config"は設定ファイルで、cowboyの依存を追加するために編集する。

"hello_server/apps"ディレクトリにはアプリケーションが配置される。rebar3のreleaseプロジェクトはumbrella projectと呼ばれていて、複数のアプリケーションを持つことができる。

"hello_server/apps/hello_server"はrebar3がテンプレートから生成したアプリケーションだ。このディレクトリ内には"src"ディレクトリがあり、3つのファイルが作成されている。"hello_server_app.erl", "hello_server_sup.erl", "hello_server.app.src"だ。

"hello_server_app.erl"はapplication behaviourを実装するソースファイルだ。

"hello_server_sup.erl"はsupervisor behaviourを実装する。今回は編集しない。

"hello_server.app.src"はapplication resource fileを生成するためのソースファイルだ。Erlang VMをどのように実行するかということを設定するためのファイルだ。rebar3はこのファイルから実際のapplication resource fileを生成する。このファイルも編集する。

Cowboyを依存に追加

Cowboyを依存に追加してrebar3にダウンロードしてもらう。そのために"hello_server/rebar.config"を編集する。

$ vim rebar.config

最初の数行は以下のようになっている。

[erl_opts, [debug_info]}.
{deps, []}.

[relx, [{release, {hello_server, "0.1.0"},
...

今回編集するのは2行目、つまり"{deps,[]}."という部分だ。このlistのなかに依存を記述していく。記述のフォーマットは様々だが、すべて"{ package_name, ...}"という形のtupleになっている。このチュートリアルではパッケージをhex.pmからダウンロードしてくるので、フォーマットは"{ package_name, "version number"}"になる。本チュートリアルを執筆時点で、最新の安定版のcowboyのバージョンは2.7.0だ。


{deps, [
    {cowboy, "2.7.0"}
]}.

rebar3は依存ライブラリが必要になった時に自動的にダウンロードするが、今回は正しく記述できていることを確認するために明示的にダウンロードしてみよう。

$ rebar3 upgrade

次に、アプリケーションリソースファイルを編集して、cowboyを先にスタートさせるようにする。今実装しているアプリケーションはcowboyを使っているので、cowboyを先にスタートさせておかなければならない。その設定方法として、"hello_server.app.src"を編集する。

$ vim apps/hello_server/src/hello_server.app.src

このファイルの中身を抜粋すると以下のようになっている。


{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib
    ]},
  ...
  ]}.

applicationsのtagged tupleの中のlistに"cowboy"を追加する。

{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib,    % カンマを忘れないこと
     cowboy     % この行を追加
    ]},
  ...
  ]}.

これはErlangのlistなのでカンマを忘れないようにすること。

HTTPサーバーの始動

容易が全て整ったので、HTTPサーバーを開始する。まず"apps/hello_server/src/hello_server_app.erl"を編集する。

vim apps/hello_server/src/hello_server_app.erl

このソースコードはrebar3によって生成されたapplication behaviourを実装するためのモジュールだ。start/2を変更して、HTTPサーバーを開始する。

start(_StartType, _StartArgs) ->
    hello_server_sup:start_link().

HTTPサーバーを開始してコネクションをlistenするには、まずcowboy用語でルートと呼ばれているものを設定する。これは特定のリモートホストやパスをcowboy_handlerに関連付けるための設定だ。ルートを設定するにはcowboy_router:compile/1を使う。この関数は引数としてcowoy_router:routes()型を取る。型は"[{Host, Pathlist}]"となっている。PathList型を展開すると、"[{Host, [{Path, Handler, InitialState}]}"となる。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { Host, [{Path, Handler, InitialState}]}
    ]),
    hello_server_sup:start_link().

ホストとして'_'を指定すると、任意のホストからのコネクションを受けつける。ホストを制限したい場合、例えばlocalhostからの接続しか受け付けたくない場合は、<<"localhost">>を指定する。

今回の場合、Pathは<<"/">>だ。今回は"http://localhost/aa/bb/cc"のようなPathは受け付けないのでこれでいい。

Handlerにはhello_handlerというatomを指定する。これは後でcowboy_handler behaviourを実装するモジュールとして実装する。

特に状態は持たないので、InitialStateは空のlistを使う。

すべてまとめると、以下のようなコードになる。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, [] }]
    ]),
    hello_server_sup:start_link().

ルートが準備できたので、HTTPリスナーを開始する。ここでは素のHTTPを使うので、cowboy:start_cear/3を使う。引数はstart_claer( Name, TransportOpts, ProtocolOpts )だ。

NameはこのHTTPリスナーを識別するための名前で、ErlangのTermであればなんでもよい。通常はatomが使われる。ここでは"hello_listener"を使う。

TransportOptsには様々なオプションがあるが、このチュートリアルではlistenするポートを指定するだけだ。今回はHTTPサーバーのポートはは通常80だが、今回は8080を使うので、"{{port, 8080}}"となる。

ProtocolOptsでは先程設定したrouteを指定する。ProtocolOptsの型はmapで、envというキーがあり、値はdispatch型だ。ここに先程束縛したDispatch変数を指定する。

成功した場合、start_clear/2は{ok, pid}を返す。okのtagged tupleに束縛することで失敗時のことはapplication behaviourにまかせよう。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, []}] }
    ]),
    {ok, _} = cowboy:start_clear(
        ello_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch}}
    ),
    hello_server_sup:start_link().

接続の処理

HTTP listenerの用意が出来たので、やってきた接続要求を処理していく。そのためにはさきほどのhello_handlerを実装しなければならない。これはcowboy_handler behaviourとして実装する。まず新しいソースファイルを作成する。

$ vim apps/hello_server/src/hello_handler.erl

まず基本的なところを埋めていこう。

-module(hello_handler).
-behaviour(cowboy_handler).
-export([init/2]).

init( Req, State ) ->
    {ok, Req, State}.

Reqはリクエストとレスポンスを保持している。Stateは好きに使える状態だが今回は使わないので空のlistとする。

やるべきことは、HTTPステータスコードとして200を返し、ヘッダーのcontent-typeとしてはtext/plainを指定し、コンテンツは"hello,world"とするだけだ。これにはcowboy_req:reply/4を使う。引数の型は"reply(Status, Headers, Body, Req)"だ。

StatusはHTTPステータスコードで型はnon_reg_integer()もしくはbinary()だ。今回は200を指定する。

HeaderはHTTP headerをmap()で指定する。今回は"content-type"を"text/plain"にする。

Bodyには<<"hello,world">>を指定する。

Reqは現在のReqオブジェクトだ。

replyは新しいReqオブジェクトを返す。これ以降Reqオブジェクトを使う際には、この新しいReqオブジェクトを使わなければならない。

init/2のコードは以下のようになる。

init( Req, State ) ->
    Req_1 = cowboy_req:reply(
        200,
        #{<<"content-type">> => <<"text/plain">>},
        <<"hello,world">>,
        Req
    ),
    {ok, Req, State}.

プログラムの実行

$ rebar shell

確認しよう。

$ curl "http://localhost:8080/"
hello,world

次はErlangのエラー処理について書こうと思う。Erlangのエラー処理はその場で処理を中断して無視していい場合は簡単だが、エラーに明示的な対処が必要だととたんに面倒になる。

2020-04-07

Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

This is the quick walkthrough of implementing and executing a HTTP server that just return hello world by using Erlang, Cowboy and rebar3.

The goal is, while executing this problem, the following happens.

$ curl "htttp://localhost:8080/"
hello,world

Erlang and Cowboy is easier compared to the god-forsaken rebar3. Rebar3, as its name indicates, had major backward incompatible breaking changes twice, and it still has many technical debt piled up on it. Even the official documentation is unhelpful at this time. I wasated months just figuring out the basics and I write it down here so you don't have to.

Prerequisites

You need Erlang implementation, rebar3. The cowboy can be fetched by rebar3.

To install erlang on debian-based distro:

$ apt install erlang

To install rebar3 in most GNU/Linux distros, you should built it yourself.

$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap

This create a file "rebar3". You can copy this file to somewhere in the PATH or symlink it.

ln -s rebar3 /usr/local/bin

Now you're ready to start using the rebar3.

Creating a new project.

First, you must create a new rebar3 project. Let's call it "hello_server".

$ rebar3 new release hello_server
$ cd hello_server

This command create a directory "hello_server" and bunch of template files in that directory. I don't explain everything in details, but just for the important bits.

"hello_server/rebar.config" is a config file we have to modify to add cowboy as an dependency.

"hello_server/apps" directory contains apps. rebar3's release project is called "umbrella project", it can contains multiple "apps".

"hello_server/apps/hello_server" is the default apps the rebar3 generated from the template. Inside that directory, there is a "src" directory which contains three template files. "hello_server_app.erl", "hello_server_sup.erl" and "hello_server.app.src".

"hello_server_app.erl" is a source file we modify.

"hello_server_sup.erl" is for implementing supervisor behaviour. We don't modify this file in this walkthrough.

"hello_server.app.src" is a source file for application resource file. It tell the Erlang VM how to start the application. Rebar3 just copy it to the appropriate place so you don't have to. We modify this file too.

Adding cowboy as an dependency

Next, we need to add cowboy as an dependency so the rebar3 can fetch it. To do so, open the "hello_server/rebar.config".

$ vim rebar.config

The first few lines are like these.

[erl_opts, [debug_info]}.
{deps, []}.

[relx, [{release, {hello_server, "0.1.0"},
...

We need to modify the second line, that is "{deps, []}.". You can add dependencies in the list. There are many formats for that but every thing is tuple of "{ package_name, ... }". In this walkthrough, we fetch the package from hex.pm. So the format shall be "{ package_name, "version number"}". As of this writing, the latest stable version of cowboy is 2.7.0.


{deps, [
    {cowboy, "2.7.0"}
]}.

rebar3 fetch the necessary dependency automatically when it is needed, but let's just fetch it explicitly to make sure we wrote it correctly.

$ rebar3 upgrade

Also, we need to modify the application resource file to start cowboy before our application. Since our application requires cowboy, the cowboy application must be started before our application. To do so, modify the "hello_server.app.src"

$ vim apps/hello_server/src/hello_server.app.src

The part of the content of this file should looks like this.


{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib
    ]},
  ...
  ]}.

We add "cowboy" to the list.

{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib,    % don't forget comma
     cowboy     % add this line
    ]},
  ...
  ]}.

As you see, this is Erlang's list so don't forget the comma before cowboy.

Fire up the HTTP server

Now we're going to start the HTTP server. First, we modify the "apps/hello_server/src/hello_server_app.erl".

vim apps/hello_server/src/hello_server_app.erl

This source code is generated by rebar3 to implement the application behaviour. We are going to modify the start/2 to fire up the HTTP server.

start(_StartType, _StartArgs) ->
    hello_server_sup:start_link().

In order to start the HTTP server listening the incoming connection, we first need to set what cowboy call it "route". It's a mapping of the connection from some remote hosts, path to cowboy_handler. To do that, we use cowboy_router:compile/1 which take a parameter of type cowboy_router:routes(). The type is "[{Host, PathList}]", if you expand the PathList type, it'll be "[Host [{Path, Handler, InitialState}]]".

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { Host, [{Path, Handler, InitialState}]
    ]),
    hello_server_sup:start_link().

The Host can be '_' which means we allow the connections from any hosts. If you are to allow connection from anywhere, use '_', if on the other hand, you want to restrict the access only from, say, localhost, it would be <<"localhost">>.

The Path in our case is <<"/">>. Since we don't support path like "http://localhost/aa/bb/cc".

For Handler, we specify "hello_hander" atom which we have to implement it as a cowboy_handler behaviour later.

We don't use state so the IinitialState be emply list.

Putting all togather so far, the code looks like this.

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, [] }]
    ]),
    hello_server_sup:start_link().

Now we prepared the route, we're going to fire up the HTTP listener. We are going to use good old plaintext HTTP by cowboy:start_clear/3. The three parameters are "start_clear(Name, TransportOpts, ProtocolOpts)".

Name can be any Erlang term to refer this listener, but atom used used most of the time. Let's use "hello_listener".

TransportOpts has many options, but for this walkthrough, we only need to set the port to listen to. We going to listen port 8080 so it would be "[{port, 8080}]".

In ProtocolOpts, we use the route we made earler. The type of ProtocolOpts is a map which as a key env whose value is also a map which has a key dispatch. We pass Dispatch for the value of this key.

If succeeded, start_claer/2 return "{ok, pid}". Let's make sure it returns ok and fail otherwise.

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, []}] }
    ]),
    {ok, _} = cowboy:start_clear(
        ello_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch}}
    ),
    hello_server_sup:start_link().

Handling the incoming connections.

Now the HTTP listners are up and running, we need to implement the hander for the incoming connections. For that, we need to implement the hello_handler we specified earlier by following the cowboy_hander behaviour. Create a new source file .

$ vim apps/hello_server/src/hello_handler.erl

Let's write the basics.

-module(hello_handler).
-behaviour(cowboy_handler).
-export([init/2]).

init( Req, State ) ->
    {ok, Req, State}.

Req represents requests and response. We don't use State really. It's just an empty list.

All we need to do is return a HTTP status code 200, the content-type is text/plain, it's content is "hello,world". We can do that by cowboy_req:reply/4. The parameters are "reply(Status, Headers, Body, Req)".

Status is a HTTP status code in non_neg_integer() or binary(). In this case, it's 200.

Header is a map() to specify HTTP header. we set it's "content-type" to be "text/plain".

For the Body, we return "hello,world".

Req is a current Req object.

reply return a new Req object which we must use it instead of old Req objects after the call.

And now, the init/2 code.

init( Req, State ) ->
    Req_1 = cowboy_req:reply(
        200,
        #{<<"content-type">> => <<"text/plain">>},
        <<"hello,world">>,
        Req
    ),
    {ok, Req, State}.

To run the program

$ rebar shell

Now to confirm it.

$ curl "http://localhost:8080/"
hello,world

If I have in the mood, I'll write the error handling next. The reality is more verbose than textbook.

2020-04-04

2019-2020シーズンに行ったスキー場の感想

2019-2020シーズンは腕も上達したし雪が少なかったこともあって普段は行かない様々なスキー場に行った。ここにその感想を簡潔にまとめておこうと思う。

まずは白馬にあるスキー場からだ。2月上旬というハイシーズンに行ったはずなのに、あいにくとほとんどの日は雪質がわるかった。

栂池高原スキー場は白馬にあるスキー場だ。白馬駅からバスで行ける。特徴はゴンドラでふもとから山頂まで一気に上がって長距離を滑ることができる点だ。とはいってもあいにくの暖冬でふもとは雪質が悪かったので、ゴンドラの中間駅まで滑ってゴンドラを往復していた。

白馬コルチナスキー場は白馬にあるスキー場だ。朝早くの行きは白馬駅から電車とバスで、帰りはバスになる。白馬はパウダーキチガイのオーストラリア人で占拠されているので、開き直ってコース外のほとんどを自己責任で滑走可能なエリアとして解放してしまったスキー場だ。コースのどこからコース外に出てもふもとの同じ場所に帰ってくることができるので、コース外を滑るには適しているスキー場と言えるだろう。白馬コルチナスキー上の横には白馬乗鞍温泉スキー場があり、共通リフト券が買えるのだが白馬コルチナスキー場からは接続が悪かったので買う価値はわからなかった。

白馬五竜とHAKUBA 47は2つのスキー場が併設されているがリフト券も共通なので実質一つのスキー場だ。白馬五竜のほうはなだらかで広いゲレンデがあり雪質の悪さと相まって面白さがわからなかったが、HAKUBA 47はなかなか面白かった。

次に赤倉温泉のスキー場だ。周辺にはもっとスキー場があるのだが、今回は2つしかいかなかった。この暖冬の3月上旬にもかかわらず雪が豊富にあった。もっとも、例年はもっと雪が多いらしいのだが。

赤倉温泉スキー場は赤倉温泉の宿が密集する場所の近くにある。スキー場としては初心者向けでほとんどなだらかなコースしかない。一箇所だけ急なコースがあるのだが、そこに上がるリフトが今にも壊れそうでとても怖い。あまりにも簡単すぎるスキー場だったので、初日の足慣らしや最終日の疲れた足でのんびり滑る分にはいいが、連日でいく価値は見いだせなかった。

赤倉観光リゾートスキー場は赤倉温泉スキー場のとなりにあり、相互に連絡できるが、リフト券は別だ。こちらはとても面白いスキー場で難しいコースもあり、連日行く価値があった。ゴンドラで上がって4km滑ることができるのもよい。

これで今シーズンは滑り納めにしようと思っていたのだが、3月24日に越後湯沢にそれなりの雪が降ったので、25日に急遽日帰りで向かった。今年のかぐらは周りのスキー場が雪不足に悩む中、標高が高くて雪があるということで大勢の客がいる上、ゲレンデまでロープウェイで上がらなければならない。しかも2019年の大型台風19号の影響で下山コースが破壊されており、帰りもロープウェイに乗らなければならない。待ち時間が数時間にもなるおそれがあり、行きたくない。ちょうどコロナウイルスが騒がれていた頃でもあったので、人が密集するロープウェイも避けたい。

そこで、神立スノーリゾートに行った。このスキー場、去年までは神立高原スキー場という名前だったはずなのだが、なぜか名前を変えている。別にリゾートと言うほどの規模のスキー場ではない気がするし、周辺にホテルが密集しているわけでもない。

スキー場自体の作りは小さいながらもよい。リフトに一本乗って2km弱ぐらいのなだらかなコースを滑ることができるし、非圧雪もあるし、きれいに形成されたコブ斜面もあり、万人の需要を満たす作りになっている。

2020-03-29

村上原野(ボレロ村上)の思い出

村上原野(ボレロ村上)の思い出を色褪せないうちに書いておこうと思う。

村上原野の父親であり師匠であった猪風来は縄文土器による芸術家である。縄文土器の制作方法を復元した人物だ。

猪風来プロフィール | 美術館の紹介 | 猪風来美術館

縄文土器は窯を使わずに野焼きで焼き上げる。野焼きで窯ほど燃焼温度が上がらないので、低温でも焼き上がるような粘土を使わなければならない。その製法は再発見され、村上原野が縄文土器作成を学ぶ頃には、一通り完成していた。製法を復元した上で、その製法を使って芸術品を作るというのだ。

聞いた話では、猪風来は極めて形から入る芸術肌の人間で、縄文人の心を理解するために、北海道に竪穴式住居をこしらえて家族で住んでいた。つまり、村上原野の父親と母親と本人は中学生か高校生ぐらいまで北海道の竪穴式住居に住んでいたのだ。

竪穴式住居とは歴史の教科書にも出てくる様式の原始的な家だ。地面を掘り下げ、その上に屋根を設営する家だ。竪穴式住居は全国にあるのだが、北海道のような寒い地方では、寒さ対策のために地面をかなり深く掘り下げる。猪風来がかつて展示会で語っていた話では、竪穴式住居の中で座ると、ちょうど目の高さが地面すれすれになるほどだという。そうして猪風来は縄文人の心を会得した。

その後、村上原野の一家は岡山の廃校に引っ越す。廃校を作品制作の作業場と作品の保管所と美術館として利用している。

村上原野はそのような特殊な家庭環境にもかかわらず、当初は高専を卒業し、確か本人の話では製図技師か何かで数年、民間で働いていたそうだ。ただし本人曰く「やはり土をいじっている方が楽しい」ということで仕事をやめ、家業をつぐことにしたのだという。

村上原野のいでたちは、かなりガッシリとした体格で、よく日焼けしていて、母親の作った作務衣を着ている。どこから見ても偉丈夫であり、刺しても死なないほどの健康な見た目であった。

このブログの読者が知る村上原野は、ボレロ村上、もしくは中3女子という名前で知っている人物で、C++プログラマーだ。

https://github.com/bolero-MURAKAMI/Sprout

Sproutは村上原野によるC++ライブラリであり、C++におけるコンパイル時計算用のフレームワークを提供している。

このSproutを使った村上原野の作品としては、コンパイル時レイトレーシングがある。

constexpr レイトレーシング - ボレロ村上 - ENiyGmaA Code

当時の純粋なテンプレートメタプログラミングのみのレイトレーシングや、あるいはC++11時代のまだ本体はreturn文ひとつしか書けなかった頃のconstexpr関数を使ったレイトレーシングがある。

あるいは、コンパイル時音声生成がある。

constexpr で音階生成&シンセサイザー&音声合成 - ボレロ村上 - ENiyGmaA Code

生前の村上原野に、C++によるこの作品は芸術なのかと聞いてみたことがあるが、彼にとってこれらは芸術ではないらしい。

村上原野 aka ボレロ村上, 中3女子 逝去

ボレロ村上、中3女子ことC++プログラマーで陶芸家の村上原野の訃報が流れている。それによるとどうやら、2月16日未明に、陶芸作品を製作中に倒れ、翌朝に発見されたようだ。

2月15日の21時51分のtweetに体調の変化を示唆する書き込みがある。倒れたのが16日の未明とあるので、そこから6時間後ということになる。

この書き込みから急な脳梗塞ではないかと思われる。体調の変化を感じたら病院に行くべきなのだろう。

大一報はおそらく猪風来美術館のFacebookで、これは20日に公開されたとのことだが、我々プログラマーの界隈に知られるまでに9日間を要したようだ。

岡山にある猪風来美術館は村上原野とその両親が経営している廃校を利用した美術館と製作所のはずで、すぐにでも岡山に行きたい気持ちがあるのだが、あいにくと世間にはコロナウイルスが流行している。行けば至近距離で会話をしたくなるだろうから、東京に住んでいる身としては軽々と訪れることができない。早くコロナウイルスが収束してほしい。

ゲンヤよ!

2020年2月16日未明、おまえは32歳という若さでこの世を去った。最後の作品を制作中、倒れる直前粘土をひと掻きした跡そのままに、手に竹べらをもったまま息絶えた。きらめく魂、やさしい魂、躍動する魂よ、おまえのすべての命が燃え尽きたのだ。 力いっぱい、こんなに精一杯生きて、表現して、苦悩し、愛して、未来へ、新しい地平へ翔けていくはずだったおまえは、今力を尽くして、生命を生き切って、美しい魂の宿る作品を私たちに託して旅立っていった。

おまえの大きな縄文の渦はここから湧きあがり、おまえはその渦に乗りここから翔けあがり、おまえの愛した山や海や大地をめぐり、生まれ育ったアイヌモシリや遥かなアメリカの大地をめぐる。おまえの渦はしなやかに美しく螺旋を描き、無数の夢を乗せて伸びやかに繋がっていく。おまえが見た精霊たちは、今おまえの後を追って螺旋の渦をなし、ひきもきらさず列をなしている。

そして渦に乗ったおまえは何度もなんどもこの地に戻ってくるだろう。まわりの森の木々を震わし、みんなで協力して建てた竪穴住居の茅屋根を撫で、野焼きの野炉の灰を散らし、おまえやほかの人の作った縄文作品を愛で、いつも、どこでも残った私たちにおまえの記憶を喚起させるだろう。おまえの成し遂げた仕事、思索、大きな夢、愛する人たち、すべてがここにあったのだから。

おまえはここで新しいおまえの地平を切り開き生きていくはずだった。縄文のスピリットに惹かれ、現代に生きる己の感性で縄文の新時代の美を求めてひたすらに挑戦を続け、その手でやり遂げていく意欲に溢れていた。私たちは底のない悲しみの中、その夢を引き継ぎ繋いでいかなければと、今祈るような気持ちで歩み始めようと思う。

生前、村上原野を支え、愛し、共に力を携えて活動してくださった方々に感謝の思いでいっぱいです。これから私たちは心を寄せる人たちと共に彼の魂の宿る最後の作品を無事焼き上げます。そして彼の残した作品を新しい縄文芸術として世に提示していきたいと思っています。彼の縄文の渦はまだ終わっていないのですから。どうぞこれからもよろしくお願いいたします。

(猪風来・むらかみよしこ)

猪風来美術館 - ゲンヤよ!... | Facebook

2020-03-08

赤倉温泉スキー場に来ている

2月に白馬に2週間滞在してスノーボードと温泉三昧だった。白馬に2週間も滞在することになったのには長い話があるのだがまたの機会に書くとして、結果として、長期滞在して温泉に浸かりスノーボードをしてリモートワークをする価値に目覚めてしまった。3月も同じことをしたいと思ったので、人を誘って再び一週間の長期滞在をしてきた。

滞在先は赤倉温泉だ。詳しくは知らないが、この暖冬にもかかわらず全国のスキー場の積雪ランキング上位にあるスキー場だ。予約時に300cmの積雪があったので、これならば雪はあるだろうと宿を予約した。赤倉ホテルという宿だ。さぞ予約は取りづらいだろうと思っていたが、あっさりと予約を取ることができた。

宿はなかなかよかった。食事は悪くなく、宿の建物内に温泉が3箇所あり、しかも2箇所は24時間入り放題。そしてもう一つ露天風呂があり、これがやや特殊な完全な外に設置されている露天風呂で、涼しくて湯温も高く最高だった。この露天風呂、変わったことに混浴でかつ周りから丸見えなのだが、そもそもホテルにはほとんど客がいないので気兼ねする必要はなかった。ただし、例年では雪が高くつもり、完全に周囲から隠れてしまうそうで、本来は女性客も入りやすいそうだ。

肝心のスキー場だが、宿の目の前に赤倉温泉スキー場がある。当初、このスキー場にのみ行くだろうと思って、あらかじめリフト券を4日分手配しておいた。しかし、これは間違いだった。赤倉温泉の近くには赤倉温泉スキー場、赤倉観光リゾートスキー場、杉ノ原スキー場、池ノ平スキー場、関温泉スキー場がある。特に赤倉温泉と赤倉観光は隣り合ってつながったスキー場で、赤倉温泉スキー場は広くて簡単でつまらないコースばかりだが、赤倉観光リゾートスキー場の方は難しくて面白いコースが多かった。

まず移動日は滑らず、初日は赤倉温泉スキー場で足慣らし、白馬で2週間、1日滑って2日休むという筋肉を鍛えるのに理想的な頻度で滑っていたので、体には余裕があった。2日目に赤倉観光リゾートスキー場に行ったが、これまた前日の疲れがまったく気にならないほどの余裕があった。3日目は流石に連続しては辛いだろうと赤倉温泉スキー場でのんびりと滑ったが、これまた余裕があった。4日目は再びリゾートに行った。5日目は念の為に休みを入れた。膝は多少痛むが、危険な痛みではない。

これを書いている時点では土曜日だが、明日の日曜日に1日滑り、月曜日は余力があれば午前中に滑って帰ってこようと思っている。こんなにも膝と脚に余裕ができているほど体が鍛えられているとは自分でも驚いている。しかも、スノーボードの腕も上達している。白馬でスイッチができるようになったが、さらに滑走が安定した。

白馬での目的はスイッチだったが、今回の目的はGoProを持っている友人と一緒に言ったので、追い撮りと自撮りの上達を目標にした。そのために自撮り棒を購入した。結果は大成功だった。もっと難しいものだと思っていたのだが、自撮り棒を持っての滑走はほとんど滑走に影響を与えない。簡単であることがわかったので、GoProの来年のモデルが販売されたら購入を検討しようと思う。

今回使ったGoProはHERO 7だが、使う上での注意点がいくつかあった。まずGoProはバッテリーが持たない。リフト営業開始から終了までの丸一日の全滑走を撮影したいというのであれば、4K解像度や120FPS撮影は諦めた上で、予備のバッテリーを2つ以上持っていくのがよいだろう。逆に、事前に危惧していたSDカードの容量は全く問題がないことがわかった。今は512GBや1TBのSSDカードが数万円で売られている。動画のビットレートが90Mbpsであったとして、512GBあれば12時間は撮影できる計算になる。そしてGoProのバッテリーは1時間持たない。

GoProを撮影した後の注意点もある。GoProはSDカードのフォーマットにexFATを使っている。exFATのfuseではないマウントにはLinux kernel 5.4が必要だ。Ubuntu 19.10は5.3、Ubuntu 20.04が5.4になる予定となっている。

GoProが使う動画フォーマットはh.265(HEVC)の10bitプロファイルを使用している。この動画のリアルタイムデコードはとても重い。筆者はここ10年ぐらいCPUのパフォーマンスは十分すぎるぐらい向上したので、いまだにSkyLake世代のIntel CPUを積んだラップトップを今回の旅行に持参した。ところが、H.265 10bitのデコードのハードウェア支援はSkyLakeの次の世代のKirbyLakeが必要だ。KirbyLakeもそうだが、AMDやNvidiaのGPUのハードウェアデコード支援も、h.265 10bitに対応したのは2016年に販売された製品からだ。今回の撮影は2.7k 60fpsで行ったが、筆者のPCではリアルタイムデコードできなかった。前のフレームからの差分で表現するIフレームや、前後のフレームからの差分で表現するBフレームを多用するh.265の再生は、リアルタイムデコードが出来ない場合破綻する。そのために当初は単に映像を確認するためだけにffmpegでh.264にエンコードしていたが、いろいろと試した結果、ブラウザーを実行しない状態でmpvを使うとややフレームレートに違和感はあるものの、再生できることがわかった。

2.7k 60fpsでこの負荷なので、4K 60fpsはもっと負荷が高いのだろう。GoProで撮影した動画を編集するには最新の高スペックなコンピューターを容易すべきだ。最も筆者はffmpegのフィルターでできる以上の編集をするつもりはないのであまり気にしていない。今のところ考えている編集は動画の切り出しと連結、あとは別音声のmuxぐらいだ。今回撮影した自撮りと追い撮りはすぐにでも動画サイトにアップロードしたいのだが、現在滞在している宿のWiFiの帯域は20Mbps程度で2割程度のパケットロスが発生するという基本的人権がないほど貧弱な環境なので、自宅に帰ってからアップロードする予定だ。

追い撮りと自撮りについてだが、まず自撮りについては特に難しいことはなかった。単に自撮り棒をもって滑るだけだ。スノーボードは両手が自由なので様々な持ち方ができる。360度カメラではない自撮り棒に固定したカメラの場合、後ろ手で持って山側から谷側への撮影、前の手で持って谷側から自分を含む山側を撮影、前の手で持って谷側を撮影という方法が考えられる。全て試してみたが、どれも特性の違う動画ができあがる。

追い撮りは難しい。単に追いかけて被写体をフレーム内に納めるだけならそれほど難しくはないのだが、問題は距離だ。GoProは画角が広い。これは被写体をフレーム内に維持するという点ではいいのだが、実際の距離以上に被写体との距離感が出てしまう。被写体を大きく移すには近づく必要があるのだが、これも難しい。被写体は自分ではないので滑走の速度があわない。直滑走すると追い越してしまうし、丁度いい速度を保つのが難しい。撮影中、離されたので直滑走して追いつき、そして抜きそうになったので減速してまた離されることがたびたびあった。これは自分のショートターンの腕前を上げるほか、被写体と無線で連絡を取り、離されすぎた場合減速してもらうなどの連携が必要だろう。

もう一つ難しいのが、実際に見たとおりに撮影できないということだ。雪面は日光の反射で白飛びしてしまい、起伏が目立たなくなってしまう。かなり深いコブ斜面でもまるで圧雪されているかのようになだらかに見えてしまう。そして、傾斜も実際より浅く見える。これはカメラ自体が傾斜にそっているために仕方がないことではある。カメラを水平にすると撮影できるのはほとんど空だけだ。速度感も乏しい。カメラを高い位置で保持すると全く速度感がない。それなりの傾斜のある斜面を直滑走しても、雪面が白飛びすることと画角の広さのせいで、全然速度が出ているように見えない。速度感を出したければカメラを低い位置に置かなければならない。

また、今回は追われ撮りもためしてみた。これはカメラを後方に向けて滑り、被写体に追いかけてもらうことで、被写体を全面から撮影しようという試みだ。これはある程度はうまくいったが、なかなか難しい。減速やターンをするたびにカメラを左右に降ってしまうので、被写体はフレームに入るためにかなり努力して滑らなけれならない。直滑走すると被写体と撮影者の道具と技量と体重差によって速度差が出てしまうので破綻する。今回、私はスノーボードで友人はスキーだったが、私は毎回ホットワックスをしているが友人はスプレーワックスで済ませるズボラな人間であるのと、私が友人より20kg重いために、直滑走すると友人よりかなり相対速度が開いてしまう。それに、被写体一人だけで同じ姿勢を維持して直滑走し続ける動画はそれほど映像映えしないという問題もある。複数人でのレースのような面白さを追加する要素が必要だ。

手ブレ補正も一長一短がある。GoProの手ブレ補正はなかなかに優秀ではあるのだが、手ブレ補正をかけると滑走のダイナミックな動きが消えてしまう短所もある。

友人はスキーヤーなので、スキーでの自撮りや追い撮りを模索していたが、自撮りについては圧倒的にスノーボードのほうが楽だ。追い撮りもスキーでは細かい調整が聞かずに難しい。ヘッドマウントではカメラ位置が固定されてしまい、自撮り棒を動かすというダイナミックな撮影ができない。スキーで自撮り棒をもつと滑走が難しくなる。スノーボードでは手を固定して滑ることもできるが、スキーは手を動かしてバランスを取りたい特性があるようだ。

今回、自分の滑りを追い撮りしてもらう機会にも恵まれたが、やはり滑走中にバランスを取るために上半身をリーンする癖が抜けない。下半身の屈伸だけで十分にバランスをとれるところでは積極的に下半身を意識して使っていきたいところだ。

2020-02-16

C++20標準規格がほぼ固まった

2020年2月10日から15日までプラハで行われた会議により、C++20のDIS(Draft Intarnational Standard)が可決された。これはC++20となる標準規格と同じ文面であり、もうこれ以上変更はない。今後、このドラフト案に対して各NBによって可否の投票が行われる。何事もなければこのまま可決されてC++20が制定されるだろう。

今回残念なのはstd::formatだ。これはpythonにあるようなテキスト整形ライブラリだ。ただしロケールに依存している。std::formatのロケールを引数に取らないコンストラクターはグローバルなlocaleオブジェクトに依存する。今の所ロケールの影響を受けるのはtype specifier nで、数値を桁区切りにして出力する機能だ。

std::formatがlocale汚染されたことにより、std::formatは危なくて使えないライブラリになったし、ローカライゼーションの妨げになるので使ってはならないライブラリとなった。

10年前、char8_tの必要性を標準化委員会に説いたときはchar型は生のバイト列を表現するのに最適な型だなどととんでもない話を持ち出されて一笑に付されたが、その後にchar8_tの必要性は認識され、かつcharが生のバイト列を表現するのに不適切な型であることが認識され、std::byteが入った。

コルーチンも問題が多い。C++20に入ったコルーチンとはその名前で連想するようなユーザーモード実装の軽量スレッドではない。C++20のコルーチンとは3種類のキーワード、co_await/co_yeild/co_returnを使った関数をコルーチン関数と認識し、その関数に対してあらかじめ定められた変形を行い、最終的にユーザー定義のクラスの特定のシグネチャーのメンバー関数を呼び出す単なるシンタックスシュガーだ。変形ルールを考慮した上で自力でライブラリを実装すれば、例えばユーザーモード実装の軽量スレッドやジェネレーターやメソッドチェインやステートマシンや非同期I/Oといった機能を実現できる。ただし、コルーチンをサポートした標準ライブラリは存在しないので自力で実装する必要がある。そして自力で実装するのは極めてだるい。

コルーチンのためだけにコア言語にここまでユーザー定義クラスの特定のシグネチャが存在することを前提とした文法を入れるのは汚い。コルーチンのような機能は、静的リフレクションで実現すべきだ。

今現在、環境の変化でC++に時間を割くことができていないし、C++20本は出せるかどうかわからない。

2020-01-18

Erlangについて思うところ

職場の今までいた部署が潰れてしまったので、新しい部署で仕事のためにErlangを学んでいる。基礎的な文法については学び終わったので、現時点でのErlangについての雑感を書いておこうと思う。

Erlangは多数派のプログラミング言語とはだいぶ違う文法を持っている。終端記号がドットであることもそうだが、比較演算子もだいぶ違っている。多くの言語が!=を使うなか、Erlangは/=を使っている。Less than or equal toが=<であるのも多数派とは異なっている。ただし、Greater than or equal toは>=だ。一貫性がない。

終端文字はドットだが、関数の中には一つの式しか書くことができない。式はカンマで区切ることができるので、以下のようになる。

func() ->
    expr1 , % カンマ
    expr2 , % カンマ
    expr3 . % ドット

このような文法はリファクタリングの時に問題になる。というのも、例えば関数の戻り値をexpr3の評価結果に依存した別のものにしたくなったとき、

func() ->
    expr1 , % カンマ
    expr2 , % カンマ
    expr3 . % エラー
    expr4 .

うっかりドットをカンマに修正するのを忘れるとエラーになる。

そもそも関数の文法も問題だ。関数は同名の関数群をセミコロンで区切って一度に定義する文法になっている。

Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr . 

関数群の最後はドットで終端するが、途中の関数はすべてセミコロンで区切る。これは関数を定義する順番を変えたときに、手でセミコロンとドットを修正しなければならない。

Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr . % エラー、リファクタリング中の修正漏れ
Name( P1 ) when ... ->
    expr ; 

変数が再束縛できないのもコードを汚くする。というのは、結局現実のコードでは式を評価した結果を元に更に計算を行い、その結果を束縛し、途中の結果については参照しないコードがある。


R1 = expr1 ,
R2 = Do_something(R1) ,
R3 = Do_something2(R2) .

もちろん、途中の評価結果を変数に束縛する必要はないのだが、あまりにも式が長い場合は可読性のために途中でわかりやすい名前をつけたくなる。しかし、変数の再束縛が許されていないために、変数名に意味のある単語を使わない文化圏の怠惰な数学者がよく使うX'や、gitを使えないバカがよく使う2020-01-18プロジェクト企画書(最新)(第二項)(承認待ち).zipのようなひどい変数名を作り散らかす原因になる。

他にもガードにBIFしか使えないとか型がないとか型がないとか特に型がないとかいろいろといいたいことはあるし、ErlangはHaskellの爪の垢を煎じて飲んでほしいのだが、汎用プログラミング言語としてみたErlangは貧弱で、主要なプログラミング言語とは違う文法を採用し、しかも融通がきかない不自然な文法で、まことにつまらない言語だ。まるでGOやJavaのような言語と言える。

ただ、言語としてはそれほど難しい概念もないので、習得は容易だろう。

ただし、あらゆる点で言語としておそまつな点が目につく。最初はクソ言語と思っていたが、途中からこれはBrainfuckと同じエソテリック言語の仲間だと思えてきた。

そして基礎的な文法を一通り学び終えた今では、ついにあるひとつの結論に達した。Erlangは分散コンピューティング用のDSLなのだ。SQLとかシェルスクリプトと同じであって、汎用プログラミング言語として考えるからクソ言語だと思うのであって、特定の分野専門のDSLだと考えれば悪い言語ではない。汎用プログラミング言語として考えたとき、SQLやシェルスクリプトはいかにもクソ言語というしかない。しかし、SQLやシェルスクリプトの価値はそこにあるのではない。Erlangも同様に、たまたま汎用プログラミング言語としての機能を備えてしまっただけで、本来は単なるDSLであり、ツールでしかない。1980年台にネットワーク越しのリモートコンピューター群をあたかも一つのコンピューターを扱っているかのように扱えるようなツールを実現したという点で価値がある。

さて、Erlangの基礎的な文法は一通り理解したのだが、まだこれでErlangの習得が終わったわけではない。これからErlangのプロセスやメッセージパッシングなどを学ばなければならない。まだもう少し時間がかかりそうだ。

膝の痛みがなかなか治らない

スノーボードによる膝の痛みがなかなか治らない。

30を超えてから新しい運動を始めると悩まされるのが靭帯と腱の損傷だ。筋肉痛というのは数日で回復するが、靭帯と腱の回復には数ヶ月かかる。これまでにボルダリング、ダンス、スノーボードと新しい運動に挑戦し続けているが、そのたびに靭帯と腱を損傷している。

残念ながら今の日本語圏のインターネットにはまともな情報がないので、せめて自分の怪我の状況と回復時の自覚症状ぐらいは書き残しておこうと思う。

ボルダリングでは指の腱を損傷した。原因は単純で、足を滑らせて指だけで極端な荷重変化を支えてしまったのが原因だ。指の腱を損傷すると、指の曲げ伸ばしと手首、手首の下辺りに違和感を感じる。回復の自覚症状はかなり急峻だ。病院に行ったところ、抗炎症作用のある塗り薬を処方された。塗るとわずかに痛みが減る。最初の一ヶ月ぐらいはほとんど回復が見られず絶望的になるが、ある日を境に1日単位で違和感が減っていく不思議な自覚症状の変化が現れた。

ダンスでは足首が痛くなった。つま先を上げる方向に足を動かすと、足首が痛くなる。医師の診断によるとアキレス腱を痛めたそうだ。一ヶ月ほどダンスを中断して、痛みがやや収まったものの、依然として残るので病院に行ったところ、処方はロキソニンテープとジクロフェナクNa(鎮痛抗炎症剤)とレバミピド(胃薬)とアセトアミノフェン(解熱鎮痛剤)であった。薬の鎮痛効果により痛み自体は軽減されるのだが、痛みがなくなるわけではなく、回復して痛みが減ったのか、単なる鎮痛効果で痛みがわかりにくくなっているだけなのか判断に困る。そのまま更に1ヶ月ほどは自覚症状は変わらなかったが、ある時を境に急激に1日単位で症状が軽くなっていった。

そして今悩まされているのが膝だ。原因はスノーボードだと思われる。ダンスで膝を痛めなかったのはよくわからない。いかにも膝に負担の掛かりそうな動きもしたのだがダンスでは問題がなく、スノーボードに1日行っただけで極端に膝を痛めてしまった。

当初は右膝の内側に痛みがあったのだが、今は左膝も少し痛み、かつ膝の外側にも痛みがある。膝の内側の痛みしか自覚症状がなかったときに医者にかかったところ、膝関節内側側副靱帯(MCL)を痛めたのだろうということだ。処方は足首と同じだ。

肝心の治療経過だが、一ヶ月経過した今、まだはかばかしくない。未だに痛みが残っている。当初は階段を上がるととても大きな痛みがあったが、今は階段を上がるぐらいでは痛みはでない。当初は膝に負荷をかける動きをすると痛みが出ただけで、安静にしていれば痛みはなかったのだが、今は膝に負荷をかけても痛みはそれほどないが、常に膝に違和感を感じている。この安静時の違和感は安定せず、痛みがないときもあれば、痛むときもある。自覚できる痛みがないからとうっかりと地下鉄の階段を上がってしまった翌日は痛みが出ている気がするので、膝への負荷に遅延して安静時の痛みが生じているのかもしれない。

靭帯と腱の回復には2ヶ月かかるという個人的な経験則からすると、回復にはまだ一ヶ月かかる計算になる。スノーボードのシーズンは短い。特に今年は雪が少なく例年より短くなるだろう。

この記事をここまで書いてから2日立った。たまたま膝の調子が良かったのでボルダリングに行ったところ、回復の兆しを感じた。翌日も痛みがあまり膝に残らない。

改めて考えてみると、今まで靭帯や腱を痛めたときの痛みの自覚症状は、いつも同じような状況だ。まず受傷直後はそれほど痛くない。翌日から数日も痛みはあるもののそれほど痛くはない。ただし、少しでも負荷がかかったならば危険な痛みを感じるので運動はできない。その後一ヶ月以上、運動を完全に控えても痛みが収まらない状態が続く。多少の負荷をかけても当初感じた危険な痛みはないのだが、やはり痛みはあるので運動はできない。このような状態が一ヶ月以上続いて絶望するが、ある時急に回復の兆しを感じる。そうすると少しぐらいは負荷を書けても痛みは感じなくなり、運動も様子を見ながら再開できる。そして、不思議なことに運動をすると回復が早まる。

2月にはスノーボードに復帰できるかもしれない。

2020-01-05

2020年の日本には2020年にふさわしい日本語の掲示板がない

情報の流通において最も効率的なのはテキストだ。テキストを効率よく流通させる方法として、古典的なインターネットにはメール、チャット、掲示板があった。

このうち、メールは古典的なEメールがまだ生き残っている他、現代的なSNSがメールの機能を代替し始めてきた。日本では今の所LINEが最も普及しているようだ。

チャットもそうだ。古典的なIRCはまだ生き残っている。しかし現代的なSNSや、Slackのようなサービスが代替し始めてきている。

では掲示板は? 現代の日本には現代的な掲示板サービスが欠けている。

もちろん、掲示板機能を提供するWebサービスはたくさんある。しかし、日本語圏でWebサービスを提供しているものは、いずれもかなり限定的な目的に特化したものだ。例えばユーザー同士で質問と回答をしあうサービス(Yahoo知恵袋など)とか、ソーシャルニュースアグリゲーション(はてなブックマーク)のようなサービスはある。しかしテキストの流通機能としては貧弱であり掲示板ではない。

2ch/5chのような古典的な掲示板はある。しかし見たところ技術的負債と開発リソースの不足により、ほとんど当時のまま運用されているようだ。2020年に使いやすい作りではない。

私の考える2020年の品質の掲示板とは、RedditやHacker NewsのようなWebサービスだ。どちらもソーシャルニュースアグリゲーションだ。そういう意味でははてなブックマークはとてもいい線を行っている。しかしはてなブックマークは掲示板ではない。単に1行コメントが書けるだけで、他人のコメントを参照してテキストを積み重ねることができない。はてなブックマークはソーシャルニュースアグリゲーションというよりはオンラインブックマークとして設計されているので、結果として掲示板にはならなかった。

結果として、日本には2020年にふさわしい現代的な掲示板がない。ないということはどこかが作れば儲かるのではないかと思う。誰かがやってほしい。

Arch Linuxがパッケージ圧縮フォーマットをxzからzstdに変更

Arch Linux - News: Now using Zstandard instead of xz for package compression

Arch Linuxがパッケージの圧縮に使うフォーマットをxzからzstdに変更した。

Archでは圧縮レベル20を使うことにより、xzにくらべて0.8%サイズが増加するが、デコード速度が1300%向上するという。

CanonicalによるUbuntuは2018年にzstdに移行するテストをしていて、その結果による、圧縮レベル19を使うことにより6%のサイズ増加だったということだ。

zstdとはFacebookのYann Colletが2016年に発表した圧縮フォーマットとそのリファレンス実装のことだ。軽く調べてみたところ、メモリ使用量が多く並列実行に力を入れている設計と実装のようで、現代のコンピューター向けという感じがする。

2020-01-04

未来のタクシーはネットカフェになる

深夜にのんびりとRedditを眺めていたところ、以下のような1年前の記事が話題になっていた。

Mean streets: Self-driving cars will "cruise" to avoid paying to park

内容はこうだ。自動運転が実用化されたならば、車は駐車せずに自動運転で周辺を運転するようになる。なぜならば、燃料費と摩耗費よりも駐車料金のほうが高くつくからだ。

たしかに一理ある。都市部の駐車料金は高い。なぜなら土地が高いからだ。自動運転により人件費がなくなれば、後は「車の燃料費と摩耗費<駐車料金」であるならば車を運転し続けたほうが安い。

この考えを推し進めると、将来、タクシーはネットカフェになる。

ネットカフェは簡易的な個室とインターネット、マンガや映画を提供している。貧乏人はネットカフェを簡易宿として利用している。これらネットカフェの機能は、自動運転による無人タクシーで代替できる。

つまりこうだ。都市部を自動運転による無人タクシーが流している。客はこのタクシーを呼び止め中に乗る。中にはフラットに倒すことのできる椅子とコンピューターと携帯電話網によるインターネットが提供されている。またマンガや映画のストリーミングサービスも提供されている。客がネットカフェ機能を利用している間、この無人タクシーは周辺、あるいは指定した目的地まで運転する。この無人タクシーは簡易宿としても利用できる。客は椅子をフラットに倒して寝ることができる。その間もタクシーは周辺を運転する。

荒唐無稽だとも思えない。現実のネットカフェは、土地と建物を用意するのに大掛かりな費用がかかる。しかも場所は固定で、車のように柔軟ではない。

どの程度現実的なのだろうか。車の摩耗費、メンテナンス費用、通信費用、コンテンツ契約費は償却して無視するとしよう。後に残るのは燃料費だ。現在、日本のガソリン価格はレギュラーが146円/Lだ。最新のハイブリット車は20km/Lを上回る燃費を持っている。

ただ、このネットカフェとしての無人タクシーにおいて、燃費というのは「距離/燃料」ではない。本当の燃費は「時間/燃料」だ。このネットカフェとしてのタクシーは走行をしなくても常時電力が必要なので、停止していても燃料を消費する。運転は燃料消費を最小にするが、走行距離を最大にする必要はない。たとえ信号や渋滞や燃料補給によって都合よく停止している時間が長くても、燃料消費が少なければ問題はない。

もしガソリン1リットルで1時間の燃費(時間/燃料)があるのだとしたら、1時間あたり146円の費用がかかる。

あるいは、蓄電池を搭載した完全電動車とすることもできる。この場合、無人タクシーは充電拠点の周辺を運転することになる。

都心部のネットカフェの料金と比較してみよう。都心部のネットカフェの相場は、30分で300円、3時間で千円、6時間で2千円、12時間で3千円程度だ。自動運転による運転手の人件費のかからない無人タクシーとしてのネットカフェは物理ネットカフェと同じ料金で利益を出せそうだ。

では肝心の駐車場の料金はどうだろう。都心部の駐車場の料金はまちまちだが、無人タクシーは場所の利便性を考えなくてもよい。利便性の悪い場所にある駐車場は、都心部であっても夜中は500円といった安いところもある。長時間利用する客を乗せた無人タクシーは、安い駐車場が空いているのならば駐車場を使い、そうでなければ道路を燃費(時間/燃料)のよい運転で流すのがよいだろう。

高度な自動運転が実用化され、このようなネットカフェとしての無人タクシーが大量に公道を流すようになると、公道が渋滞して社会問題になるはずだ。しかし法改正は技術開発よりも時間がかかるはずで、このような未来はありうるのではないか。

2019-12-18

江添自宅ボドゲ会@12月22日

以下の要領で12月22日に自宅ボドゲを開催します。

https://ezoe.connpass.com/event/159944/

今回はコルトエクスプレスのもう一つの方の拡張がしたい。