2018-10-14

消費税について考えたこと

「消費税10%は100円が110円になると考えるのではなく、1000万円が1100万円になると考えるべきだ」というつぶやきを目にした。しかしこれは言っていることが同じだ。

私はむしろ、消費税とは手取りに対する税金ではないかと考えている。貯蓄をしない家計では、消費税は実質手取りに対する税金だ。貯蓄をしない家計にとって、消費税10%とは、手取り20万円が18万円になることだ。

もっとも、この考え方にも問題はある。というのも貯蓄をしない家計は賃貸住宅に住んでいるだろうが、不動産の貸付料である家賃には消費税はかからない。手取り20万円の家計で家賃6万円の場合、14万円が12万6千円になるということだ。

消費税と言えばイタリアは先進国だ。1973年という昔から12%の消費税を導入し、1997年には20%に引き上げられた。そのイタリアでは、表に出ず消費税を脱税した地下経済とマフィアが発展した。

消費税が10%ともなると、日本でも地下経済と、地下経済の信用取引を履行させるためのヤクザが発展するだろうか。

日本ではヤクザの人権を剥奪する法律によりヤクザの人口が急激に減りつつある。また個人間の送金手段は経済に悪影響を及ぼすほど厳しく規制しているので地下経済も発展しにくい。

とはいえ、消費税があまりにも高くなれば地下経済は発展するだろうし、地下経済が発展したならば、その信用取引を確実に履行させるための機関としてヤクザが必要になり、ミカジメ料を支払うようになるのでヤクザも再び興隆するだろうか。

ということを考えながら、消費税制度の解説を眺めていたところ、興味深い定義を発見した。

「郵便切手類、印紙、証紙、物品切手の譲渡は非課税取引」

興味深い定義だ。すべての取引が地下経済に潜ることはできない以上、我々は表の取引もする。であれば、一部の取引を切手や印紙による取引とするのは現実的ではないだろうか。素晴らしいことに地下経済にする必要すらない。単なる非課税取引をしたにすぎないのだから。

具体的に考えよう。君は牛を二頭持っている。今君は牛を一頭売る契約をしたので契約書作成の税金を収めるため収入印紙を貼る必要がある。君は残りの牛一頭のミルクを売って現金を得て消費税を払い、残りの現金で収入印紙を買う。もし、君がミルクと収入印紙を直接交換したならば、消費税を支払う必要はない。

すばらしい。我々は現金ではなく収入印紙で支払うことによって消費税を節税することに成功した。消費税を支払わない分、ミルクの値段を下げるか、利益を上げることができる。

こう考えると、消費税の存在は貨幣経済に対する足かせであるように思えてくる。

しかし収入印紙は日本国に対する支払いにしか使えない用途の限定された通貨だ。現金という汎用的な通貨ではない。この問題をどうすればいいのだろう。

収入印紙には需要がある。需要があるものは汎用的な通貨である現金と交換できる。例えば金券ショップでは、収入印紙は額面の95%ぐらいで交換できる相場だ。ところで今の消費税は8%である。収入印紙で取引して収入印紙を現金化した場合の損失が、消費税率を下回る場合、これは得をしたと言えるのではないか。しかも合法だ。つまり収入印紙での取引は合法的な節税になるのではないか。

私は経済学にも消費税制度にも詳しくないのだが、この解釈は正しいのだろうか。

2018-10-07

Steven WeinbergのTo Explain The Worldを読んだ

邦訳では「科学の発見」という題名がついているSteven WeinbergのTo Explain The Worldを読んだ。

著者のSteven Weinbergはノーベル物理学賞の受賞者でイスラエルの熱烈な支持者だ。

冒頭で「本書で筆者は過去を現代の基準で批判する愚を犯す」と書きながら、この本は科学がどのように発展してきたかを解説している。

本書はまず、古代ギリシャにおける万物を構成する元素の説について取り上げる。古代ギリシャの哲学者が、元素は水だとしたり、火だとしたり、水、火、土、空気の4種類だと主張している歴史を取り上げる。

ここまではまあいいとして、プラトンの提唱した説を取り上げて悶絶する。プラトンは四大元素である火、水、土、空気について、とても小さい元素が存在し、5種類ある正多面体をそれぞれ割り当てた。たとえば火は正四面体で、水は正二十面体といった具合だ。その仮説を立てるのはいいとして、割り当ては一体どういう理由で行われたのか。プラトンは単にそれが理想だからとしか語らない。

科学というものは、まず観測し、観測結果から仮説を立て、仮説が観測結果に従うことを検証するものだ。

しかし古代ギリシャでは、科学は科学ではなく哲学で、単に理想を追求するものでしかなかった。なので万物を構成する元素は元素は火や水といったわかりやすい理想的なものになり、元素は5種類ある正多面体であるとし、完全数を尊びといった、現実の観測結果より理想を追求し、理想が現実に従わないことは無視されていた。

その後、本書の大半は天体の運行の予測を通じた科学の発展に費やされる。

天体の運行には規則性があり、古代から占星学などの存在により、天体の運行を正確に予測する需要があった。

古代ギリシャ時代から地球が中心で月、惑星、太陽、その他の恒星は全て地球の周りを回っている説が主流であった。

古代ギリシャ時代にはすでに地球を中心とした天体の運行を予測する数式モデルが考案されていたが、他の天体はすべて地球を中心とした真円で回るなどと定義されていたため、現実の観測とは大いに異なっていた。しかも、それぞれの天体が謎の理由で割り当てられた正多角形に内接する真円で回るなどという、これまたプラトンのように理想を追求したモデルであった。

天体は地球を中心に真円で回転するモデルを使うと、惑星はある時期だけ逆方向に回りだしたりする。惑星が大抵の言語で語源からして、惑う星であるのも、これが原因だ。

そこでプトレマイオス説が考案された。この説では、天動説で現実の観測結果に近似させるために、あまりにも無理やりな天体のモデルを考案した。天体は太陽を中心に真円で回っている。この真円を従円と呼ぶ。天体は従円を線上を中心としてさらに真円で回っている。この真円を周転円と呼ぶ。

プトレマイオス説は複数の真円を組み合わせ、真円の大きさをパラメーター化することで、惑星の運行を現実に近似させることを試みた。その結果、かなりの制度で現実の観測に近似した天体モデルを作ることに成功した。

プトレマイオス説は科学だ。観測から観測結果に従う数式モデルを作ったわけで、これは科学と言える。

プトレマイオス説は哲学者からは理想ではなく天体の予測のための方便であるとされていた。天文学者(この時代の天文学者は占星学をかねる)は積極的に使っていた。というのも、プトレマイオス説は現実の観測結果の近似していて、予測に役立つからだ。

その後、様々な天文学者がプトレマイオス説により複雑な周転円を追加することで、さらに現実の観測結果に近づける努力が行われた。

太陽を中心として天体が公転している地動説は以前にも理想として提唱されたことはあったが、現実の観測結果を説明できる具体的な数式モデルはコペルニクスによってまず作られた。ただし、コペルニクスの数式モデルは精度が悪かった。というのも、コペルニクスは天体は太陽を中心に真円で公転していると定義したが、実際には太陽は中心ではなく、天体の公転軌道は真円ではないからだ。

本書は中東の科学についても解説している。中東の科学はイスラム教の普及によって妨害されるまでヨーロッパより進んでいた。ギリシャ時代の学説は中東からもたらされる形でヨーロッパに再発見された。その後イスラム教の普及により中東の科学の発展は阻害された。

そしてガリレオ・ガリレイの時代までやってくる。ガリレオ・ガリレイは優秀な望遠鏡を発明し、望遠鏡によって精密な天体観測をした。その結果地動説を唱えるわけだが、その上でパトロンであるローマ教皇を天動説を信じているなどと批判したので宗教裁判にかけられて地動説を封印する。後世に残る逸話によれば、このときガリレオは「それでも地球は回っている」とつぶやきながら法廷を後にしたと言われる。

宗教裁判の後、ガリレオは晩年まで自宅に軟禁状態におかれるわけだが、ガリレオの科学への情熱は冷めていなかった。ガリレオは落下する物体の速度について研究していた。落下する物体の速度を観測するのは当時としては難しい。というのも、速度が速すぎるために正確な観測ができないためだ。

ガリレオはこの落下速度の問題に対し、科学的な観測方法を考案する。緩やかな傾斜面を転がる球を使うことで速度の計測を可能にした。時間の計測には水時計を使った。傾斜角を変えることでガリレオは速度は傾斜角に比例することを示し、傾斜角を転がる球は落下速度の計測の代わりに使うことができることを示した。もちろん現実には、球と傾斜面の摩擦にもエネルギーが使われるが微々たるもので当時実現可能な観測方法としては十分なものだった。ガリレオは傾斜角を転がる球を机の端から飛ばし、その軌道が放物線であることも観測している。

本書はニュートンの説明に移る。ニュートンによって科学革命はクライマックスを迎えるわけだが、しかしこのニュートンという人物はなんという奇人だろうか。ニュートンは生涯、イングランドのごく狭い地域より外に出ることはなかった。ニュートンは潮の満ち引きについて多大なる関心を持っていたにもかかわらず、生涯一度も海を見ることはなかった。中年に至るまでニュートンは身近に女を寄せ付けることがなかった。母親とて例外ではない。50代になってから親戚の美しい娘を家政婦として雇っているが、この2人の間に男女関係はなかった。ニュートンは科学以外にも、非科学的な錬金術や宗教について多大な著作を残している。

ニュートンの研究者の間でよく言われることには、ニュートンは最初の科学者ではない。ニュートンは最後の魔法使いである。時代が魔法から科学に変わる節目の時期にあって、魔法から科学への橋渡しをした人物だ。

ニュートンの法則を記述したPrincipiaは、単に重力を説明し得たために偉大だというわけではない。ニュートンはPrincipiaによって、物理的現象は簡単な数学的原則と、その原則の応用で説明できることを示したのだ。

中国の悪意あるハードウェアの細工を見破る方法

中国で生産されているハードウェアに悪意あるチップが取り付けられておりAppleやAmazonが被害にあっているとする報道があり、真偽について議論がある。

これに関連して、Hacker Newsで興味深いコメントが寄せられていた。

I have worked in card payment industry. We would be getting products from China ... | Hacker News

俺はカード支払い業界で働いている。中国から送られてくる製品にクレジットカード情報を送信する装置が取り付けられていることがある。これは国家による攻撃ではない。装置は生産ラインの途中で取り付けられている。大抵は賄賂を受け取った従業員によるものだ。装置が組み立てられた後は、改造防止の機能が動くので、改造を検知させずに装置を分解するのは不可能だ。

この問題が発覚してから、我々は製品の重さを計測することにした。我々も製品を分解することはできないからだ。分解したならば改造検知により装置は動かなくなる。

攻撃者は重さの計測に気がついたので、製品内部の必須ではないプラスチックを引っぺがして装置を追加することによって増加した重さの調整をしてくるようになった。

結局、我々は特別な土台を使い製品の角運動量(訳注:慣性モーメントか)を計測するようになった。とても高価な装置で角運動量を計測する。俺が作った土台を使って2つの角度から角運動量を計測している。2つの製品の角運動量がどの角度からでも一致するならば製品は同一というわけだ。すべての角度から角運動量を計測できないが、今のところ破られていない。

角運動量ではなく慣性モーメントだろうという用語の甘さや、慣性モーメントは3軸を使って全角度を測定できるのではというツッコミが入っているが、この話自体はよくあるものらしい。

なんでそんな製造段階で悪意ある細工が混入した製品を送ってくるところと取引を続けるんだというコメントに対し、この製品を製造しているのは今や中国をおいて他にないとか、中国の商習慣では信頼を前提としない契約による取引に応じてくれないとか、中国と取引するには製品の欠陥は自前で発見できなければならない、発見できないのはマヌケな顧客であり欠陥品で十分だとみなされる、などの中国のお国柄を指摘するコメントが続いている。

2018-09-20

健全なP2Pネットワークの信用のためには全利用者の参加が必須であるという話

「Zaifが5966BTCやられたようだな」
「ククク、あれは後発取引所ゆえ保有量が最弱」
「85万BTCを溶かした余の足元にも及ばぬ」

また一つ暗号通貨の取引所が失敗した。人はいつになったら学ぶのだろうか。中央権威のないP2Pネットワーク上の信頼は、利用者全員が参加することでしか担保できぬと。

信じられないことに、暗号通貨の利用者の中でも、なぜ暗号通貨が信用できるか、というより暗号通貨の何を信用しているかを理解しているものは少ない。皆暗号通貨と日本円などの国家通貨の交換レートしか気にしていない。国家通貨との交換レートなど、暗号通貨の実現している技術的な価値に比べればチリほどの価値もない。暗号通貨の価値は、中央権威のない通信越しに偽造できない通貨の取引を実現したということにある。

問題を簡単にするために、暗号通貨とは違う例で考えよう。

アリスとボブが仕切りを隔てて音声による会話しかできない状況に置かれている。この状況で、アリスとボブはコイントスによる勝負をする。コイントスは投げたコインが表か裏のどちらを上にして落ちるかで勝敗が決まる。アリスが表で勝つのであれば、ボブは裏で勝つ。アリスが裏ならばボブは表で勝つ。

アリスとボブが賭ける表裏を音声による会話で選択したとして、一体どうやって信頼できるコイントスをすればいいのだろうか。アリスとボブのどちらか一方がコイントスをして結果を相手に伝える場合、音声による会話しかできないので、相手はコイントスの結果を信用できない。アリスとボブ以外に勝負の審判をしてくれる都合のいい第三者はいない。

実は、この状況でアリスとボブがどちらも信用できるコイントスを行うことは数学的に可能だ。

では問題を変えよう。ここに60億人の人間がいる。全員、音声による会話しかできない。60億人のうちのある一人のアリスが、ある一人のボブに自分の持っている通貨の支払いたい。支払った後のアリスは通貨を失い、ボブは通貨を得る。しかし全員音声による会話しかできないのに、どうやったらそんな取引が信用できるのだろうか。

これも、数学的に信用できる方法がある。bitcoinを始めとする暗号通貨が行っているのはこれだ。

信用を担保するには、60億人が全員同じ方法で数学的な計算を行い、不正がないことを確かめなければならない。もし、30億人と一人が不正のための計算に協力したならば、アリスが支払ったはずの通貨はアリスの手元に残り、ボブの手元には通貨がない常態にすることも可能だ。しかし、そのような参加者の過半数を超える大規模な計算は難しい。

ただし、この方法で信用できるのは、ある暗号通貨の取引だけだ。暗号通貨と日本円の取引とか、物の取引は暗号通貨の信用の範囲外だ。

残念ながら、世の中の暗号通貨利用者の大半はズボラで、自ら信用を担保することを考えていない。こういうマヌケ共は、自ら信用のための計算をせずに、取引所と呼ばれる他人に計算を任せる。本来ならば証明された数学と計算力を信用すればよいはずの暗号通貨を、他人の信用に置き換えてしまう。こうなるともはやその計算を任された取引所が権威となり、単一障害点になってしまう。その結果、取引所が失敗すると任せていた全員が失敗する。

人はいつ学ぶのだろうか。

そういえば、CloudflareがIPFSのゲートウェイを提供するという興味深いニュースがあったので、今はIPFSについて学んでいる。今学んだ限りでは、名前解決であるIPNSを除けば、IPFSが喧伝していることはBitTorrentプロトコルに対するフロントエンドで実装できそうで、あまり目新しい価値はないように思える。そして、Cloudflareのような大手がゲートウェイを提供し、皆が自前でフルノードを動かさずにゲートウェイに依存することで、健全なP2Pネットワークの信用が損なわれてしまうだろう。

2018-09-17

Linus、今までの行いを謝罪し一時的にカーネルメンテナーの立場を退いて人の気持ちを勉強してくると発言

完全に背景事情を調べ上げたわけではないのだが、どうもLinusが毎年参加しているLinuxカーネルの会議に、Linusがスケジュールを間違えて参加できなくなるという事態が発生した。当のLinus本人はもう20年も続いている会議だし自分がいなくてもやっていけるだろうと楽観視していたが、会議自体がLinusの都合にあわせてリスケジュールされた。

LinuxにおいてLinus Torvaldsといえば第一人者であり極めて重要な存在で、そのLinusが毎年参加している重要な会議にLinusが参加できないとあれば、その他のあらゆるコストを度外視して根回し調整を行い、Linusが参加できるようにイベント全体のリスケジュールを行うのは人間の感情から考えて当然である。しかし当のLinus本人は他人の感情が読めず、そこまでの大事になるとは考えていなかった。その認識の差が今回の騒動に発展した。

Linux 4.19-rc4 released, an apology, and a maintainership note - Linus Torvalds

[ その他の長々しい話 ]

いつもの発表とは違う先週のことについて。メンテナーとカーネルコミュニティについての、公になっているカーネルサミットによるものと様々なプライベートなやり取りの議論について。議論の一部は俺がメンテナーサミットのスケジュールを間違えたから起こったわけだが。

こういう議論は今週になって初めて始まったわけでもない。メンテナーとコミュニティについては長年議論してきたわけだ。プライベートでもメーリングリストでもたくさん議論されてきた。カンファレンスでも毎回トークがあるし、これも、一般向けのものと、廊下を歩きながら話す種類のものがある。

先週がいつもと違ったのは、俺の反応と、俺が反応しすぎたためだ(判断は読者に任せる)

要するに議題は2つある。

ひとつは俺がメンテナーシップサミットのスケジュールでヘマをやらかしたことに対する俺の反応だ。いや、実際日付を間違えたのは失敗だったが、でも正直なところ、俺がここ20年ぐらい参加していたカーネルサミットに今回ぐらい参加しなくてもいいんじゃないかと思っていたのだ。

実際には、サミットがリスケジュールされたし俺の「俺なしでもやれるんじゃない」って意見は覆されたわけだ。だがこの状況が別の議論の呼び水になった。これが議題の2つめにかかってくるわけだが、俺は気がついたんだよ。俺って人の気持ちが読めないんじゃないのってことに。

要するに「鏡で自分の顔を見てみろよ」って瞬間だな。

というわけで、俺がついに気がついたこととして、俺が毎年のカーネルサミットを今回ばかりパスするのは面白くもないしいい兆候でもないってことと、俺は今の今までコミュニティの気持ちを汲み取れていなかったということだ。

何というかな。無視できるってものは、だいたい俺が首を突っ込みたくないものなんだな。

これが俺という人間の現実だ。俺は他人の感情を読み取るのが得意ってタイプの人間じゃないし、そのことはみんなも当然気がついていただろうから驚きはないだろう。俺以外はな。俺が長年、他人の気持ちを読み取れずにいて、大人でない環境を作り出していたってのは良くないことだ。

今週、コミュニティ内の人間は俺が人の感情を理解できていないということについて批判してきた。俺の反論は大人気なかったし良いものでもなかった。特に俺個人の問題としたことについてだ。俺がよりよいパッチを追求することについて、これは俺の中では当然のことだ。これはどうもよろしくない態度だと気がついたわけで、正直すまんかった。

こうくどくど書き連ねているのはつまり俺が誤りを認めて、おいおい、お前は態度を改めなければならんぞ、という辛い思いをかみしめているのであって、俺の態度で気分を害したりカーネル開発から抜けてしまった人間にあやまりたい。

ちょっとここらで休みを取って、他人の感情を理解する方法と、適切な応対の方法について、誰かから学んでくる。

別の視点で考えると、カンファレンスに呼ばれた時、俺はよく、カーネル開発の厄介な問題点はたいてい技術的な問題ではなくて、開発フローと態度の変化の問題なのだというトークをよくする。

この厄介な問題点というのは、パッチを管理する方法とか、やり方の大規模な変更とかだ。「パッチとtar-ball」によるリリース(15年前に「Linusはスケールしない」という厄介な議論が持ち上がった原因)から、BitKeeperを使う方法に変わり、それも無理になってきたのでgitを使う方法に変わった。

そういう厄介な問題点は、ここ10年ぐらいなかったわけだ。だが今週、それに匹敵する厄介な問題点が見つかった。

これを4.19-rc4のリリースに結びつけると(いや、実際関係しているのだが)、4.19はなかなかよいものになると思うよ。このリリースサイクルは「落ち着いた」期間になるし、Gregに話はつけておいたので、Gregが4.19を取り仕切ってくれる。その間に俺が休みを取って、俺の態度について修正してくるわ。

これは「俺はもう燃え尽きた。もう逃げ出したい」っていう休みじゃない。Linuxのメンテナーを辞めたいなどとは思っていない。実際逆だ。俺はこの30年近く関わってきたプロジェクトをまだ続けたい。

これは前にもあったように、"git"という小さなツールを書くためにカーネル開発をちょっと停止するひつようがあったように、今回もちょっと休憩して、誰かに手伝ってもらって、態度を改め、俺のツールとワークフローの問題を修正するということだ。

実際のところ、修正の一部はツールで解決できるかも知れないのだ。例えば、メールフィルターをかまして、俺が罵詈雑言を含むメールを送信しようとしたら差し止めるとか。ほら、俺はツールの信者だからさ、一部の問題は、簡単な自動化で防げるかもしれないだろ。

俺が本当に「鏡を見た」とき、明らかに俺に必要なのは変化だけではないわけだが、いや、ほら・・・何か提案があったらメールで送ってくれよな。

メンテナーサミットで会えるのを楽しみにしているよ。

Linus

2018-09-10

TempleOSの作者Terry Davisが列車に引かれて死んだ

Man killed by train had tech following | The Dalles Chronicle

Man killed by train had tech following By Neita Cecil As of Friday, Septem - Pastebin.com

両親と喧嘩をして勘当され路上生活をしていたTerry Davis(Terrance Davis)が8月11日に列車に引かれて死んだことが確認された。享年48歳。

Terry DavisはTempleOSの作者だ。

TempleOS

読者の多くはTempleOSを知らないだろう。TempleOSとはx86-64 Ring-0上で動作するOSだ。プロセス分離はなく、メモリ保護もなく、そもそも仮想メモリではなく物理メモリアドレスを直接使うOSだ。コンセプトは古き良きCommodore 64の現代版だ。あの頃のPCはメモリアドレスは直接メモリアドレスであって、仮想メモリによってどこか不定の物理メモリアドレスにマッピングされたりなどしなかった。

TempleOSはキリスト教の影響を受けておりキリスト教の聖書やキリスト教に由来するゲームが多数入っている。

TempleOSはHolyCで書かれている。HolyCはC言語に似た文法を持っている。TempleOSのシェルはHolyCのJITコンパイラーになっていて、シェルに書き込むと、HolyCがJITコンパイルされ実行されるようになっている。

作者は統合失調症を患ったOS開発者で、大抵のインターネット上のフォーラムからは出禁の扱いを受けていた。なぜならば、Terry Davisの発言には必ず人種差別と罵詈雑言が含まれていたからだ。彼にとってほとんどの人間は「ニガーでCIAのスパイ」だと認識されていた。

Terry Davisは統合失調症の症状が強く現れてからは職を辞め、両親と同居して、キリスト教の神の神殿をコンピューター上に再現するTempleOSを開発していた。

何年もそういう状況であったが、2017年に両親とだいぶひどいいさかいを起こし、ホームレスになっていた。

ホームレスになった後も定期的に動画が上がったりなどして生存が確認できていたが、ここ最近、死亡説が噂されていた。それが確認されたことになる。

悲しい

GitHubからDXVKレポジトリが消失

GitHubのDXVKレポジトリが500を返すようになった。

https://github.com/doitsujin/dxvk

DXVKはDirectX 10/11の自由なVulkan実装だ。DXVKによってWineやProtonはDirectXの使われたWindows用ゲームをGNU/Linuxで実行することができる。DXVKにより不自由なMicrosoft Windowsはとうとうゲーム用OSとしても完全に敗北し、その座をGNU/Linuxに明け渡すことになる予定だが、どうしたことだろう。

DXVK github not found and valve's copy throws error? Whats happening? : linux_gaming

どうやら、DXVKの作者のGitHubアカウントが謎の理由でBANされたそうだ。

DXVK github not found and valve's copy throws error? Whats happening? : linux_gaming

作者によってすぐにGitLab上でDXVKが公開された。

Philip Rebohle / dxvk · GitLab

Redditでは「そういえばGitHubはMicrosoftに買収されるんだよな」というジョークが書き込まれているが、ジョークで済むだろうか。

追記2018-09-10 9:14: 復活した。

2018-09-03

江添ボドゲ会@9月8日

自宅ボードゲーム会を以下の要領で開催します。

江添ボドゲ会@9月8日 - connpass

2018-09-02

DNAの読み取りについてプログラマーが誤解していること

世の中にはDNAの読み取りを使った技術が実用されすぎている。DNAを使った生物の共通祖先の判定、人間の出アフリカ以降の移動の推定、特定の病気にかかりやすい遺伝子を持つかの判定、親子鑑定、刑事裁判におけるDNA鑑定などなど。

あまりにもDNAの読み取りを使った技術が実用化されすぎているため、世間ではDNAの読み取りは簡単なものだと考えている。プログラマーとて例外ではない。

大抵のプログラマーはヒトDNAの読み取りを以下のように考えている。

「一本の長い磁気テープを先頭から末尾までシーケンシャルにリードする」

より現実的に例えると以下のようになる。

  • 長さ30kmの長大な磁気テープをだいたい長さ1cmのテープ片に切断する
  • 上記1cmのテープ片を数百本複製する
  • 上記複製した数百本の1cmテープ片をマイクロメートル単位のテープ片にズタズタに切り裂いて混ぜ合わせる
  • 上記混ぜ合わせたマイクロメートル単位のテープ集合からランダムでテープ片を手当たりしだいに読み込み、組み合わせパズルを解いて元の1cmの磁気テープ分の正しいデータ配列を決定する
  • 残りの29.999999kmのテープについても同様に1cmづつ処理する

マイクロメートル単位のテープ片をランダムに読み取って組み合わせパズルを解き、元の1cmのテープ分のデータ配列を決定するのはソフトウェアにより実装されている。読者はそのようなパズルを解くプログラムをバグなしで実装できるだろうか。

ただし、より例え話を現実に近づけると、1cmのテープ片をマイクロ単位のテープ片に切り裂くのはランダムではない。この1cmのテープ辺には数百-2ビットから数千-2ビット程度のデータが記録されている。テープをマイクロメートル単位に切り裂くカッターは、テープの末尾の2ビットの値がn回目に出現したmであるときに切断するという条件付きカッターだ。これにより、00, 01, 10, 11のいずれかの2ビット値の1回目の出現、2回めの出現、3回目の出現といった単位でテープをカットできる。

マイクロメートル単位のテープ辺を読むリーダーはあまり融通が聞かない。すでに読んだテープ辺と同一内容のテープ編を何度も読み込むことになるし、同一内容のテープ辺は同じ回数読み込まれるわけではない。読み込みエラーが発生して任意の2ビットが別の値になってしまうかもしれない。なのでできるだけ何度も読み込み、まれにしか現れない異端データを読み取りエラーと判断して除外する処理も必要だ。

これを考えると、プログラマーとしての私は、DNA読み取りを使う技術が信頼できなくなってしまう。私のDNAを読み取った結果、特定の病気になりやすい遺伝子が含まれているとか、ある人物と親子関係にあるとか、犯行現場に残されていたDNAと一致したなどと言われても、その結果は信頼することができない。なぜならばDNAを読み取るという処理が極めて大雑把で信頼できない確率的な統計処理だからだ。

現実のDNA読み取りはどうしているかと言うと、30億塩基配列ほどあるヒトDNAを、数百塩基から数千塩基のサイズに分割し、たまたま高温に耐える都合のいい細菌から得たDNA複製酵素と一緒に容器の中に放り込み、定期的に温度を上げ下げする装置を使い、ポリメラーゼ連鎖反応を起こしてDNA片を複製する。そして特定の塩基配列に対してのみ反応してDNAを切断する酵素を使い、n回目に4種類ある塩基(アデニン、グアニン、シトシン、チミン)の特定の一種類が現れたDNAをそこで切断させる。そうやって切断されたDNA片を片っ端から読み込み、組み合わせパズルを解く。

実際、アメリカではDNA鑑定の結果が証拠として信頼できないとして、DNA鑑定に使われたソフトウェアを検証するために開示請求がなされたこともある。

せめてプログラマーだけでもDNA読み取りの正しい理解をしてほしいものだ。

ssh経由のtmuxの中で動くvimのウインドウサイズ変更にマウスを使う方法

私はマウスが好きだ。

30行以上、100列以上の文字が表示できる端末を使っている私にとっては、マウスは必須である。画面上に表示される任意の1文字にカーソルを合わせたい場合、キーボードだけでカーソルを移動させるのはとてもつらい作業である。一方、マウスならばその場にカーソルを動かすだけでよい。

端末を分割して複数の画面にする時、それぞれの画面のサイズをその場で微調整するには、キーボードで画面サイズの数値を指定するよりは、やはりマウスで直感的にドラッグしたい。

例えばvimだ。以下のようにすると

:set mouse=a

Vimはマウスを扱えるようになる。端末の任意の文字にカーソルを合わせるのにマウスを使えるのみならず、マウスでスクロールやマウスで範囲選択もできる。

Vimは画面を複数のWindowに分割できる。

:split
:vsplit

このとき、マウスを有効にしているとウインドウの枠をドラッグすることでサイズを直感的に変更できる。

tmuxも重要なソフトウェアだ。

tmuxは.tmux.confに以下の設定をすれば、

set -g mouse on

マウスを使えるようになる。マウスでスクロール、範囲選択ができるし、

Ctrl-b "
Ctrl %

で作ったtmuxのpaneのサイズもドラッグで直感的に変更できるようになる。

ところが、tmuxのなかで実行したvimのウインドウのサイズをマウスで変更できないことに気がついた。

調べた結果、これは.vimrcに以下のように書き込めばできる。

set mouse=a
set ttymouse=xterm2

どうやらxterm2にあるドラッグ中もマウス入力を通知し続ける機能を使うそうだ。tmuxも対応している。

これで問題は完璧に解決したと思ったが、もう一つ問題に出くわした。ssh先のリモートで実行したtmuxの中で実行したvimではマウスによるウインドウのりサイズができない。

これは.tmux.confに以下のように書けばできる。

set -g mouse on
setw -g alternate-screen on

man tmuxをみるとデフォルトでonになっているはずだが、なぜかUbuntu server 18.04ではonになっていないようだ。

これで以前からやりたかったssh越しにも違和感のまったくない環境を作ることができた。

2018-09-01

ポータブルオーディオプレイヤーは二極化している

今のポータブルオーディオプレイヤーは二極化している。格安のゴミみたいな製品と、オーディオフィリ向けのクソみたいな製品があり、その中間がない。

最近、減量のためにジョギングを再開した。ジョギングは一回あたり1時間ほど行うのだが、これが思いの外ヒマだ。この時間を有意義に使いたい。走っている最中にできることは音を聞くぐらいなものだ。音楽に興味はないが英語の朗読を聞くのは有意義なことのように思われる。例えば筆者はまだシェイクスピアのハムレットを読んだことがない。ハムレットを読むには時間がかかるが、ジョギング一回あたりの1時間を使えば、何度か走るだけでシェイクスピアを通して聞くことができる。

そこで早速、ジョージ・オーウェルの1984やシェイクスピアのハムレットを朗読した自由な録音をダウンロードした。

LibriVox

元々が低音質なソースであるのだから、それほど高級な製品はいらない。そこで、アマゾンでよく購入されていた適当な格安ポータブルオーディオプレイヤーであるAGPTEK A01Tと、格安BluetoothイヤホンであるSoundPeats Q30を購入した。

さっそくハムレット朗読のmp3ファイルをコピーするが、なぜか再生の順序がファイル名の文字列順にソートされない。どうやら、FAT32のファイルのディレクトリーエントリーの順番で再生されるようだ。そこで仕方なく、以下のようにして問題を解決した。

ls | while read file ; do mv $file path-to-mp3-storage/$file

いざ聞いてみると、今度は片耳にしか音が聞こえてこない。どうやらこの格安ポータブルオーディオプレイヤーは、モノラルmp3ファイルに対して片耳しか出力しないようだ。残念ながらモノラルmp3ファイルを再エンコードなしでステレオにすることはできないので、以下のようにして無駄にステレオにした。

ls | while read file ;< /dev/null do ffmpeg -i $file -ac 2 -b:a 320k path-to-mp3-storage/$file

当初動かずに困惑したが、ffmpegが標準入力を食べてしまうことが原因だった。

そしてGNU Parallelを使ったほうがよかったことに実行した後に気がついた。

mp3のエンコード速度はそれほどパフォーマンスを重視していない私のラップトップでも175倍速だった。たしか私がmp3プレイヤーを使っていた15年ほど前はせいぜい20倍速に満たない程度だった気がするのだが、いい時代になったものだ。私の一つ上の世代は、mp3をリアルタイムデコードするためにCPUをオーバークロックしたと聞く。

本の朗読を聞くために買ったのだからあまり期待はしていなかったものの、この格安ポータブルオーディオプレイヤーはあまりにもひどい品質だ。おまけに、文字コードの対応もひどい。どうやらいまだにUCSに対応していないらしく、本体の言語設定をした文字に引きづられる。例えば言語をEnglishに設定するとASCII以外が文字化けし、日本語に設定するとシフトJIS外の文字が文字化けするようだ。これは解せない。ファイルシステムであるFAT32はファイル名をUCS-2で管理しているのだから、文字化けを起こすのはわざわざ何かとてもバカなことをしているとしか思えない。

不思議なことに、このポータブルオーディオプレイヤーにはFMラジオとかテキストリーダーとか万歩計とか録音とか動画再生などの様々な機能がありながら、ファイル名によるソート機能すらない。

ではもっとマシなポータブルオーディオプレイヤーはないものか。実は今ポータブルオーディオプレイヤーは二極化しているのだ。

ひとつには私が買ったような数千円で変えるクソのような格安の粗悪品。もう一つには、最低数万円から数十万円もするようなオーディオフィリ向けのバカのような高級品だ。中間層の市場はスマフォが完全に支配してしまったため、ポータブルオーディオプレイヤーは格安と高級品に二極化してしまったのだ。

では高級なポータブルオーディオプレイヤーとはどのようなものだろうか。安いものでも数万円から、高いものになると30万円ぐらいする。30万円だ。嘘ではない。本当だ。曰くハイレゾ、曰く超高性能DAC、曰くUSB Audio/DACに両方とも対応。厳選された高性能で高品質なキャパシタ、コイル、メッキなどなど。

ちょっとまってもらいたい。人間の可聴域は若者でもせいぜい20kHz程度であり、だからこそせいぜい40KHzのサンプリング周波数で20kHzまでの音を再現できるようにしているのだ。ハイレゾに意味はない。USB Audioに対応しているのはともかくとして、なぜUSB DACとして使える必要があるのだ。そして高級なキャパシタやコイルに至っては完全にオーディオフィリの領域だ。

5000円ぐらいでまともなUIを備えたポータブルオーディオプレイヤーはないものか。そもそも格安プレイヤーにすらいらない機能が多すぎる。必要なのはファイル名によるソート、シークバー、Bluetoothだ。自由にプログラミングできればなおよい。

という愚痴を漏らしていると、物好きな同僚がRaspberry Pi Zero WHを進めてきた。初代Raspberry PiのSoCを使い、WiFiとBluetoothが搭載された低電力なボードだ。Raspberry Piはその普及によって圧倒的に自由なソフトウェアスタックを得た。その性能はmp3やoggのリアルタイムデコードを難なくこなせるであろうし、Bluetoothも使える。しかも値段も2千円程度。確かに理想的なポータブルオーディオプレイヤーのように思える。

問題はUIをどうするかだ。タッチパネル付きのディスプレイをつけるのが一番いいように思える。考えてみよう。

2018-08-23

Steam Playで不自由なWindows用ゲームをGNU/Linux上で実行するにはPython 2が必要

Steam Playが発表されたので、早速使ってみた。

Steam PlayというのはWineからforkしたValveのProtonを使ったGNU/LinuxでWindows用ゲームを実行する機能だ。なぜWineをforkしているかというと、ProtonではWineにまだ入っていない変更を使っているからだ。例えばDirectXをVulkanで実装したdxvkや、同期処理をユーザースペースで行うValveが開発したWineに対するパッチesyncを使っている。

https://github.com/ValveSoftware/Proton

Steam Playを使うには、まずSteamクライアントのSettings→Account→Beta participationからSteamクライアントBetaを使う設定であるSteam Beta Updateに切り替え、Steamクライアントをアップデートする。

すると設定にSettings→Steam Playが追加されているのでこれを有効にする。Valveが検証したゲーム以外のすべてのゲームでSteam Playを有効にするには、その設定項目のEnable Steam Play for all titlesを有効にする。これでGNU/LinuxのSteam クライアントでもWindows用ゲームがインストール、実行できるようになる。

ここまではSteamクライアントで必要な変更だ。GNU/Linux側でも必要な用意がある。Steam PlayにはVulkanに対応したかなり最新のグラフィックスタックが必要になる。

詳しい内容は

https://github.com/ValveSoftware/Proton/blob/proton_3.7/PREREQS.md

に書いてある。

NvidiaのGPUを使っている場合は、不自由なバイナリブロブドライバーを396.51以上のバージョンにしなければならない。Ubnuntu 18.04のドライバーはLatest Long Lived Branchである390を使っているので、最新のバージョンをインストールしなければならない。

sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt install nvidia-driver-396

AMDとIntelのGPUを使っている場合は、最近のMesaとLLVMをインストールしなければならない。

sudo add-apt-repository ppa:paulo-miguel-dias/mesa
sudo apt dist-upgrade
sudo apt install mesa-vulkan-drivers mesa-vulkan-drivers:i386

AMDでVRゲームを実行する場合は、以下のパッケージが必要だ。

sudo add-apt-repository ppa:kisak/steamvr4pk
sudo apt dist-upgrade
sudo apt install linux-generic-steamvr-18.04

現在、IntelのGPUによるVRゲームはサポートしていないそうだ。

DirectX 11を使ったゲームを実行するには、NVIDIA 396.51以上、もしくはMesa 18.1.xが最低でも必要だ。LLVM 7も推奨されている。

OpenCLを使ったゲーム(DOOM 2016, Google Earth VR)を実行するには、Mesa 18.2.x以上が最低でも必要になる。

一部のディストロでは1プロセスあたりのfd limitが低いので、これを変更しなければならない。4096は1990年台には妥当な値ではあったかもしれないが、この2018年には少なすぎる。DebianとUbuntuでは上限が引き上げられているので問題はないそうだ。

そして最後にとても重要なソフトウェアをインストールする。Python 2だ。

sudo apt install python-minimal

こともあろうかこの2018年にProtonとgit submoduleしているffmpegがpython 2に依存している。

これでSteam Playを使う用意が整った。いくつかのWindows用の不自由なゲームを実行してみたが、いずれもよく動いている。

GNU/Linuxにおけるゲームは卵が先か鶏が先かという問題に直面していた。ゲーム開発者はGNU/Linuxゲーマーの需要がわからないのでGNU/Linux用のゲームを出さず、GNU/Linuxユーザーは対応しているゲームが少ないので仕方がなくWindowsかWineを使うので、結果として潜在的なGNU/LinuxゲーマーはWindowsゲーマーとしてカウントされてしまう。するとゲーム開発者はGNU/Linuxゲーマーの需要がわからないというデッドロック問題だ。

Steam Playによるゲームの実行は、GNU/Linuxユーザーとしてカウントされ、ゲーム開発者に通知されるしSteamの統計にも出る。これにより我々GNU/Linuxゲーマーの時代が訪れる。Microsoftの不自由で不便で非効率的なWindowsは最後の砦であったゲーム環境としても滅ぶのだ。未来は明るい。

2018-08-14

江添ボドゲ会@8月18日

江添自宅ボドゲ会を以下の要領で開催します。

江添ボドゲ会@8月18日 - connpass

2018-08-12

違法な職務質問を受けたので国賠訴訟を起こした裁判の傍聴のお知らせ

私の裁判の傍聴をしたいという人が何人かいるので、ここで証人尋問の傍聴の告知をしておく。

  • 日時: 2018年9月19日 水曜日 13時30分から16時頃まで
  • 場所: 東京地方裁判所631号法廷

傍聴をするためには、指定の日時の少し前に東京地裁に行き、金属探知機のある入り口を通過し、そのままエレベーターで6階まで上がって時間通りに631号法廷に行くだけだ。特に予約や手続きは必要ない。また、途中退出してもよいそうだ。

裁判の内容だが、私は約1年前に警察官から違法な職務質問を受けたので東京都を相手に起こした国賠訴訟だ。

本の虫: 警察官に職務質問をされた話

本の虫: 濫用に当たる職務質問を受けたと考えたので弁護士に相談して訴訟を起こすことになった話

裁判を起こすことになって初めて知ったのだが、警察というのは地方自治体の行政であるので、東京都内で生じた警察の行為について裁判を起こす場合、被告は東京都になる。

裁判は公開かつ口頭で行われるということになっているが、その実態としては、口頭で話すべき内容をすべて書面にまとめておき、あらかじめ裁判所に提出する。書面にすべてがまとめられているので、実際の期日に物理的な裁判所でやることはほとんどない。

実際に裁判所で行われる「儀式」は以下のようになる。

裁判官「原告/被告からは準備書面が提出されていますが、これは?」
原告/被告「陳述します」
裁判官「では次回期日ですがX月Y日のZ時からでは?」
原告/被告「その日は差し支えです/大丈夫です」

事前に提出した書面について「陳述」する宣言と、証拠の原本の確認と、次回期日を決めることしかしていない。

このようなやり取りが数カ月に一回発生するのが裁判だ。1回あたり5分から10分で終わる。この裁判の傍聴もできるのだが、傍聴しても退屈なので、これまで特に案内はしてこなかった。

今回は証人尋問が行われる。証人は原告である私と、職務質問の最初から最後まで現場にいたという警察官だ。当事者ではない第三者が傍聴して退屈ではない裁判というと、まず証人尋問だろう。

ところで、今回の裁判で気になる点としては、裁判官が頻繁に交代することだ。前々回でいきなり3人全員が同時に交代したかと思ったら、前回はさらに2人同時に交代した。裁判官の一部が交代するのはよくあることだが、それでも普通は一人ぐらいは最初から最後まで同じ裁判官を残すものだという。さもなければ、判決を書く裁判官はこれまでの裁判の口頭弁論も証人尋問も直接聞かず、書面だけで判断することになるからだ。一人でも最初から担当していた裁判官が残っていればその裁判官が物理的に見ているわけだから、その裁判官が知っているということにできるが、3人同時に交代してしまってはその手法も使えない。

今後の想定としては証人尋問を経て年内には判決が出る見込みだそうだ。

2018-07-31

GCCのgit移行が難航中

GCCはgitへの移行を計画しているが、GCCの既存のsubversionレポジトリをgitレポジトリに変換する作業が難航している。

GCCの移行作業を検証しているのは他ならぬEric S. Raymond(ESR)だ。

ESRお手製の変換ツール、reposurgeonはsubversionからgitへの変換ができる。

Resource page for reposurgeon 3.44

しかしGCCは30年もの歴史を持ち、そのsubversionレポジトリも複雑だ。

ESRはGCCのためにreposurgeonのバグを潰し、勢い変換しようと試みたが、意外な障害に出くわした。メモリ不足だ。

GCC's Conversion To Git Is Being Held Up By RAM, a.k.a. Crazy DDR4 Prices - Phoronix

ESRの所有する64GBのメモリを詰んだマシンではメモリ不足で処理できない。そしてDDR4メモリの値段は高騰している。GCCのビルドサーバーに128GBのメモリを詰んだものがあるからそれを使わせてくれとか、reposurgeonをPythonからGoに移植すればメモリ消費量は減らせる可能性があるが移植は困難を極めるとか、ESRに投げ銭してメモリを買わせようなどと議論をしていたのが7月はじめ。

さて、今はメモリ以外の問題に出くわしている。

GCC's Conversion To Git Is Still Turning Out To Be A Massive Headache - Phoronix

どうもGCCの膨大で複雑な歴史を正しくgitで表現する方法について議論の余地がある他、変換結果が壊れることもある。問題を解決したいが、変換自体がとても遅いため、デバッグが困難だという。

https://gcc.gnu.org/ml/gcc/2018-07/msg00322.html

トンネル出口の明かりが見えたと思ったら対抗列車が突っ込んできやがった。

もう変換はほぼほぼ終わりだと思っていたのに。俺はtrunkとブランチすべてがクリーンに変換されるのを確認したのに。捨ててもいいことに同意した失敗ブランチただ一つを除いては。

後残っているのはexecute-permission propagationとかmid-branch deleteをどうするかという問題だけで、前者はすでに解決済みだし、後者も解決に取り掛かっている。最終的には年末には、たぶん8月とか9月には、完了できるはずだったのに。

そしたらこのザマよ。俺の最新の変換がtrunkで間違った結果を出しやがった。これは実際ヤバイ問題で、GCCレポジトリがあまりにも巨大すぎるので調査するのに時間がかかりすぎる。SVNダンプファイルをreposurgeonで読み込むだけで4.5時間かかるし、フル変換に9時間はかかる。レポジトリは俺が最適化を考えるのと同じぐらい早く増大しているぜ。

しかも悪いことに、クリーンな変換ができるコミットまで戻っても失敗する。たぶん俺がへんてこなブランチコピーの対処を実装した結果こうなってるんだと思う。

パーティーに遅れてやってきた奴のために説明してやると、Subversionのダンプファイルの処理シーケンスの解釈は単純で検証も楽だ。ブランチコピー操作を除いてはな。ブランチコピーが他の操作に及ぼす影響だけはマジで闇が深い。

Subversionのコードが何をすべきかっていう正しいセマンティクスは存在するわけだが、古のSubversion開発者が理解していたことは、今や失われている。ダンプフォーマットはまともにドキュメント化されていない。今の不完全なドキュメントが存在する理由は、他でもない俺が解析したからだ。でも俺のドキュメントも疑問だらけだし、その疑問にはSubversion開発者も回答できないできる。

なのでレポジトリを変換する際にブランチコピーに関連した謎の挙動に出くわすのはよくあることだ。普通、おれは問題のコミットをbisectして、

  1. ダンプを問題が再現する最小のセグメントに切り取る
  2. content blobsをsource commitを識別できるunique small cookiesに置換する処理を行って結果が正しいことを検証
  3. topological reduceしブランチコピーもプロパティ変更でもない無価値なコミットを除去し、結果が正しいことを検証
  4. 手動で不必要なブランチをreposurgeonで削除

いつもなら、俺は今頃、問題を再現できる割と小さめのレポジトリ(今までで200コミットを超えたことはない)を作ってる。デバッグレベルを上げて変換を観察し、何が起こっているのかを観察する。そして問題を修正し、問題を再現する最小例は新たなテストケースになるって寸法だ。

これによって、ダンプファイル解析を着実に改善していき、Subversionのコードがやっていることをより忠実にエミュレートしていく。簡単な仕事ではないが、エッジケースを埋めていくほど楽になる。今まではこれでうまくいってきた。

GCCレポジトリのサイズでは、この戦略がうまくいかない。軽く計算するだけで、bisect一回で最短でも18日かかる。現実的には一ヶ月近くかかるだろう。

つまり、現状ではゲームオーバーで負けたってことだ。GCCレポジトリはでかすぎる上に変すぎる。

この問題を現実的に解決するには、俺のツールはすっげー速くなる必要がある。だいたい桁違いに早くないといかん。

ハードウェア性能を上げるのは無理だ。シングルプロセスを1.3GHz以上にあげたコンピューターはこの世に存在しないし、問題は並列化できない。

ソフトウェアの変更でうまく行く可能性はある。俺はreposurgeonをPythonからGoに移植するということについて考えている。repocutterで実験してみたところ、{Python版の40倍高速化した。reposurgeonではそんなに高速化するとは思えないが、問題を現実的に解決できるぐらいには高速化できるだろうと踏んでいる。40倍の半分だったとしても、9時間のテストランが13分になるわけだから。

この計画の問題点は、GOに移植するのは困難を極めるってことだ。めっちゃむずい。どのくらい時間がかかるかわからんが数カ月単位でかかる。

GCCはどのくらい辛抱強く待つのか決める必要があるな。現状だと、今のソースツリーの状態をそのままgitにしていちからはじめるほうがマシかもしれん。歴史は記録だけに留めるとして。

2018-07-24

しないでマイクロソフトのスタイルガイドライン準拠の翻訳

マイクロソフトは将来的に買収する見込みのGitHubで.NETのドキュメントを公開している。ハロウィーン文書が公開された頃のマイクロソフトからは考えられないほど変わったものだ。

https://github.com/dotnet/docs.ja-jp

その中にある変数名の命名規則に関するスタイルガイドラインについて書かれたドキュメントの文章がおかしい。

https://github.com/dotnet/docs.ja-jp/blob/live/docs/standard/design-guidelines/names-of-type-members.md

しないで動詞または動詞句は、メソッドの名前を指定します。

しないで名詞、名詞句、または形容詞を使用してプロパティの名前を付けます。

しないで次の例のように、"Get"メソッドの名前に一致するプロパティがあります。

しないで後に"List"または"Collection"単数形の語句を使用する代わりに、コレクション内の項目を記述する複数形の語句でコレクションのプロパティの名前を付けます

日本語として極めて不自然な文章になっていて意味がわからない。

原文は英語で書かれている。

https://github.com/dotnet/docs/blob/master/docs/standard/design-guidelines/names-of-type-members.md

原文を確認するとようやく意味がわかる。

DO give methods names that are verbs or verb phrases.

DO name properties using a noun, noun phrase, or adjective.

DO NOT have properties that match the name of "Get" methods as in the following example:

DO name collection properties with a plural phrase describing the items in the collection instead of using a singular phrase followed by "List" or "Collection."

なるほど、"DO"を間違えて「しないで」と訳してしまったのだな。"DO NOT"も「しないで」と訳されている。翻訳する上で間違えて機械的に置換でもしたのだろう。原文の文章の形をなるべく維持したまま日本語に訳すならば、"DO"を「正:」、"DO NOT"を「誤:」とでもすればいいのだろう。ただ、その場合"DO NOT"を使った文中で代替案も示してしまっているのが問題なので、これはできれば原文自体を「すべきこと」と「すべきでないこと」に分割すべきだろう。

そして間違いが20日にissueで指摘された。

https://github.com/dotnet/docs.ja-jp/issues/118

そして土日を挟んで今日、マイクロソフトから正式に回答があった。

https://github.com/dotnet/docs.ja-jp/issues/118#issuecomment-407202477

こんにちは、@megascus

言語に関するフィードバックをお寄せいただきありがとうございました。

お寄せいただいたフィードバックの内容を Microsoft の言語チームで検証いたしましたところ、残念ながら、マイクロソフトのスタイルガイドラインに従わない という理由で、承認基準に完全には適合していないという結果になりました。

記事の品質向上にご協力いただき誠にありがとうございました。引き続きお客様からの貴重なフィードバックをお待ちしています。

敬具

Microsoft DOCS International Team

そしてissueはclosedされた。

ん? である。問題は日本語の翻訳にあるのであってソースコードのスタイルガイドラインとは何の関係もない。上記の日本語を読解できるだけの日本語能力があるならば容易に気がつくはずで、まるでBOTによってなされたような回答だ。

その結果、マイクロソフト用語では"DO"は「しないで」を意味するのだとか、マイクロソフト社内では"DO"と"DO NOT"は同じ意味を持つのだとか、Google翻訳のほうがよっぽどマシな翻訳をしてくれるとか、ユーモラスなコメントが並ぶことになった。

マイクロソフト用語を使うと以下のようになる。

DO fix the document which has a translation error.

しないで誤訳を含むドキュメントの修正

DO translate with MS style guideline conformance.

しないでMSスタイルガイドライン準拠の翻訳

押すなよ、絶対押すなよ(押せ)、というダチョウ倶楽部メソッドを久しぶりに思い出してしまった。

2018-07-13

NPMのESLintのパッケージにマルウェアが混入された問題

Postmortem for Malicious Packages Published on July 12th, 2018 - ESLint - Pluggable JavaScript linter

https://github.com/eslint/eslint-scope/issues/39

要約

2018年7月12日に、攻撃者がESLintメンテナーのnpmアカウントを不正利用し、悪意あるコードが混入したeslint-scopeとeslint-config-eslintパッケージをnpmレジストリに公開した。インストール時に、悪意あるパッケージがダウンロードされ、pastebin.comからコードを実行し、このコードはユーザーの.npmrcファイルの中身を攻撃者に送信する。通常.npmrcファイルにはnpmでパッケージを公開する際のアクセストークンが含まれる。

悪意あるパッケージのバージョンはeslint-scope@3.7.2 並びに eslint-config-eslint@5.0.2であり、すでに両方共npmから非公開になっている。このパッケージが使っているpastebin.comのリンクもすでに取り下げられた。

npmは2018-07-12 12:30 UTC以前に発行されたすべてのアクセストークンをrevokeした。この結果、この攻撃により不正に取得されたすべてのアクセストークンは利用不可能になっているはずだ。

アカウントを不正利用されたメンテナーはnpmパスワードを複数の他のサイトに使いまわしており、かつnpmアカウントに2段階認証を有効にしていなかった。

我々、ESLintチームは今回の出来事について謝罪いたします。この失敗を他のメンテナーは他山の石としてnpm全体のセキュリティを高めることを願っています。

影響を受けたパッケージ

  • eslint-scope@3.7、このスコープ解析ライブラリは他の有名な複数のパッケージから依存されている。これには古いeslintと最新のbabel-eslintとwebpackが含まれる。
  • eslint-config-eslint@5.0、これはESLintチームによって内部的に使われている設定用のパッケージであって、よそではほとんど使われていない。

独自のnpmレジストリを運営している場合、これらのパッケージから悪意あるバージョンを非公開にすべきである。npmjs.comレジストリはすでに非公開にした。

攻撃手法

攻撃手法の詳細についてはhttps://gist.github.com/hzoo/51cb84afdc50b14bffa6c6dc49826b3eを参照。

推奨

今回の事例から、我々はnpmパッケージメンテナーとユーザーが今後取るべき推奨事項をいくつか提案する。

  • パッケージメンテナーとユーザーは同じパスワードを複数の違うサイトに使いまわすことをやめるべきである。1PasswordやLastPassのようなパスワードマネージャーは使いまわさなくても済むような利便性を提供してくれる
  • パッケージメンテナーは2段階認証を有効にすべきである使い方のドキュメント。Lernaを使っているのであれば、ここも参照
  • パッケージメンテナーはnpmの公開権限を持つ人間を精査、制限すべきである。
  • パッケージメンテナーはauto-merge dependency upgradesを提供するサービスの使用に慎重を期すべきである。
  • アプリケーション開発社はlockfile(package-lock.json、もしくはyarn.lock)を使い、新しいパッケージの自動インストールを差し止めるべきである。

時系列

  • 問題発生前:攻撃者はおそらくメンテナーがよそで使いまわしたメールとパスワードが流出しているのを発見し、これを使いメンテナーのnpmアカウントにログインした。
  • 2018年7月12日早朝:攻撃者はメンテナーのnpmアカウントで認証トークンを生成した。
  • 2018-07012 09:49 UTC: 攻撃者は生成された認証トークンを使い、eslint-config-eslint@5.0.2を公開した、これには悪意あるpostinstallスクリプトが含まれ、このスクリプトはローカルマシンの.npmrcの認証トークンの取得を試みる。
  • 2018-07-12 10:25 UTC: 攻撃者はeslint-config-eslint@5.0.2を非公開にした。
  • 2018-07-12 10:40 UTC: 攻撃者はeslint-scope@3.7.2を公開した。これには悪意あるpostinstallスクリプトが含まれる。
  • 2018-07-12 11:17 UTC: ユーザーがeslint/eslint-scope#39"を投稿、ESLintチームに問題を通知。
  • 2018-07-12 12:27 UTC: pastebin.comにある悪意あるコードが貼り付けられたリンクが取り下げられた。
  • 2018-07-12 12:37 UTC: ESLintメンテナーから連絡を受けたnpmチームはeslint-scope@3.7.2を非公開にした。
  • 2018-07-12 17:41 UTC: ESLintチームはeslint-scope@3.7.1のコードをeslint-scope@3.7.3として公開した。これによりキャッシュは新しいバージョンを使えるようになる。
  • 2018-07-12 18:42 UTC: npmは2018-07-12 12:30 UTC以前に生成されたすべてのアクセストークンをrevokeした。

リンク

2018-07-11

C++20の汎用エイリアス宣言の提案

P0945R0: p0945r0: Generalizing alias declarations

提案に誤りが有りすぎる。

C++のドラフトに入る見込みが高そうな提案に、汎用エイリアス宣言がある。

C++では、名前に別名をつけることがよく行われている。

型はtypedef指定子やエイリアス宣言によって別名を付けられる。

typedef int type ;
using type = int ;

関数は転送関数を書くことにより、実質別名を付けられる。

int f( int x ) ;

int g( int x )
{
    return f(x) ;
}

ただし、値は完璧に転送できないし、関数のアドレスも異なるものになってしまう。

変数はリファレンスで別名を付けられる。

int x = 0 ;
int & y = x ;

非staticデータメンバーはストレージを消費せずに別名をつけることができない

enumeratorはconstexpr inline変数によって別名を付けられる。

enum { value } ;

constexpr inline auto flag = value ;

ただしinline変数は名前空間スコープでしか使えない。

名前空間は名前空間エイリアスにより別名を付けられる。

namespace a { }

namespace b = a ;

型テンプレートはエイリアステンプレートで別名を定義できるが、デフォルトテンプレートパラメーターまで再現しなければならない。

template < typename T, typename Allocator = std::allocator<T> >
using vec = std::vector<T, Allocator> ;

ただし、この別名は別のテンプレートとして解釈されてしまう。

コンセプトは別のコンセプトを定義すれば別名を付けられる。

template < typename T >
concept newConcept = oldConcept<T> ;

名前の種類によって別名を宣言する文法が異なるし、単なる別名以上の意味を持つものもある。

この提案では、別名の宣言をエイリアス宣言に集約する。


using alias_name = name ;

型は今までどおりだが、その他

 型、今までどおり
using type = int ;

// 関数
int f(int) ;
using g = f ;

// 変数
int x = 0 ;
using y = x ;

// 非staticデータメンバー
template < typename Type, typename Value >
struct map_node : std::pair<Type, Value>
{
    using std::pair<Type, Value>::pair ;

    using key = first ;
    using value = second ;
} ;

[]{
    map_node< int, std::string> n( 123, "123") ;
    n.key ;
    n.value ;
} ;

// enum

enum { value } ;

using flag = value ;

// 名前空間

namespace a ;
using b = a ;


// 型テンプレート

using vec = std::vector ;

vec<int> v ;

// コンセプト

using newConcept = oldConcept ;

だいぶすっきりする。とくに非staticデータメンバーがよい。

2018-07-10

C++に提案されている静的例外

C++に静的例外が提案されている。

[PDF] P0709R1: Zero-overhead deterministic exceptions: Throwing values

例外はそのパフォーマンスへの影響が懸念され、一部のC++プロジェクトではコンパイラーオプションによって例外自体が無効化されていた。

これは由々しき事態だ。というのも、例外は標準C++の機能の一部であり、標準ライブラリは例外の存在を前提にして設計されている。例外が無効化されているということは、それはもはやC++ではない。C++風の別言語を使っていることになる。

なぜ例外は忌避されるのか。例外のパフォーマンスが非決定的だからだ。例外の実装はスタックからの確保ではなくヒープからの動的なメモリ確保が必要で、例外のキャッチにはRTTIによる型情報の比較が必要だ。

ifとgotoによるエラー処理のパフォーマンス特性は決定的に見積もることができるが、動的メモリ確保のパフォーマンス特性は決定的に見積もることができない。非決定的なパフォーマンス特性を持つ処理は、例えば数ミリ秒以内に必ず処理を終えなければならないような状況で使うことはできない。

この提案では、従来の例外を動的例外とし、新たに静的例外を追加して、例外のパフォーマンスを決定的にする。

まず、静的例外では例外としてthrowできる型が制約を受ける。特別に用意した何らかのstd::error型を投げる。このerror型は内部的には整数型で、デストラクターを実行する必要がなく、サイズは最大でもポインター2つ程度を想定している。標準はこのような型をrelocatableな型として規定する。

この標準のerror型はstd::error_codeを拡張したようなクラスで、様々な一般的にエラーに用いられるカテゴリーわけされた整数を返すことができる。このerror型はC++の標準の例外型は数値で表現できるようになっているので、静的例外と動的例外は標準の範囲であれば相互に変換可能になっている。

静的例外を扱う関数、静的例外関数を追加する。静的例外関数は静的例外指定によって明示的に指定する必要がある。提案では仮に、thorwsキーワードを用いる文法を提案している。


string f() throws
{
    if ( is_error() )
        throw error::something ;
    else
        return "hoge"s ;
}

静的例外関数はあたかもnoexcept(fase)が指定されたかのように振る舞う。したがってnothrow系のtraitsもそのように振る舞う。

静的例外関数が例外を外に投げる場合、例外を従来のスタックアンワインディングを伴う例外の仕組みを使わず、戻り値で返す。つまり静的例外関数はunion { R ; E ; } + boolのような型を内部的に戻り値として返す。ようするにexpected<T,E>のような型と同等の機能を提供する型を返す。

静的例外というのはerror型の値に変換できる値を投げるthrow式のことだ。それ以外のthrow式は動的例外となる。

// 静的例外
throw error::foobar ;
// 動的例外
throw "error"s ;

静的例外関数のなかで静的例外がthrowされ、その関数のローカルに対応する例外ハンドラーがある場合、該当する例外ハンドラーにgotoでとんだものと同じ挙動をする。

 string f() throws
{
    try {
        // ローカルのcatchにgotoで飛ぶのと同じ
        throw error::something ;
    } catch ( error e )
    {
        // ここにgotoで飛ぶのと同じ
    }
}

静的例外関数のローカルに該当する例外ハンドラーがない場合、errorは戻り値として返される。そのため、上の関数は実際には、union { string ; error ; }という型とどちらのunionメンバーが有効かを示すbool値を返したものとみなされる。これは従来のreturnと同じ仕組みで実装できるので、パフォーマンス特性も決定的になる。

静的例外関数が別の静的例外関数を呼び出し、静的例外によるerror型が返った場合は、その場で静的例外がthrowされたものとみなして処理する。

string f() throws 
{
    // 内部的にはerrorがreturnされる
    throw error::something ;
}

string g() throws
{
    try { return f() ; }
    catch( error e )
    {
        // ここにgotoで飛ぶ
    }
}

静的例外関数の中で従来の動的例外が投げられた場合、それが直接throw式で投げられたにせよ、呼び出した関数を通じて間接的に投げられたにせよ、直ちにその場でキャッチされ、適切な例外ハンドラーが選ばれる。

string f() ; // 非静的例外関数
string g() throws ; // 静的例外関数

string h() throw
{
    try {
        auto a = f() ;
        auto b = g() ;
        return a + b ;
    }
    // 静的例外
    catch( error e )
    {
    }
    // 動的例外
    // 従来の非決定的なパフォーマンス特性を持つ
    catch( std::bad_alloc e )
    {
    }
}

もし、静的例外関数から従来の動的例外が投げられ、関数の中に該当する例外ハンドラーがない場合、例外の型がerrorであれば静的例外としてreturnされ、それ以外であればstd::exception_ptrで束縛されてreturnされる。

string fail()
{
    throw "always error"s ;
}

string f() throws
{
    return fail() ;
}

この関数fは、string型をstd::exception_ptrで束縛してreturnする。

std::exception_ptrはC++11から追加された例外のオブジェクトを束縛できる機能だ。もう7年前の大昔に追加された機能なので読者は当然知っているはずだ。

呼び出した静的例外関数がstd::exception_ptrをreturnした場合、その場でただちに例外オブジェクトが取り出され、例外処理が行われる。もし例外オブジェクトがerror型の場合は静的例外が、そうでない場合は動的例外として処理される。

一部のC++の標準例外は、error型に変換される。例えばstd::bad_allocはerror型である(名前は仮のものだが)std::errc::ENOMEMに変換される。

非静的例外関数が静的例外関数を呼び出して例外を受け取った場合、もしerrorに対応するstd::exception型(たとえばerrc::ENOMEMからstd::bad_alloc)があるならば型を変換して動的例外がthrowされる。std::exception_ptrの中身がerror型の場合は取り出してerror型がthrowされたものとして処理される。それ以外の例外は動的例外がthrowされる。

string f() throws
{
    // 動的メモリ確保に失敗するコード
    // return std::errc::ENOMEM ; と同じ
    string s( std::numeric_limits<std::size_t>::max(), 'x') ; 
    return s ;
}

string g()
{
    // throw std::bad_alloc; と同じ
    return f() ;
}

この提案は従来の動的例外と組み合わせて使えるパフォーマンス特性が決定的な、つまりifとgotoを使うのと全く変わらないエラー処理を、例外の文法で実現する、静的例外を提案するものだ。これによりゼロオーバーヘッドの原則を満たした例外が扱えるようになる。

興味深いので入ってほしい。例外はすべてのC++で有効化されるべきだ。例外の使えないC++はC++風の別言語なので、利用者が分断されてしまう。 

2018-07-06

江添ボドゲ会@7月15日

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

江添ボドゲ会@7月15日 - connpass

2018-07-05

プロフェッショナルIPv6の執筆経緯が興味深い

「プロフェッショナルIPv6」が出版されるそうだ。

すごいIPv6本を無料配布!:Geekなぺーじ

この本の執筆経緯が面白い。クラウドファンディングで金を集めている。

すごい技術書を一緒に作ろう。あきみち+ラムダノート『プロフェッショナルIPv6』 | クラウドファンディング - Makuake(マクアケ)

クラウドファンディングでは結果的に400万円ほど集まったそうだ。これはラムダノートと著者の連名のクラウドファンディングなので、著者の総取りというわけでもないだろうが、それにしても400万円は現代の技術書としては異例だ。

技術書とカネの話をしようと思う。私自身、技術書を出版してカネを得た経験がある。

技術書一冊の相場は数千円だ。売上一冊あたりの著者の収入は数百円だ。では著者が数百万円を稼ぐためには何冊売ればいいのだろうか。1万冊だ。問題は技術書で1万冊も売れる本は稀だということだ。1万冊売れる本というのは、技術書と言うよりはド素人に技術の仕組みをやんわりと教える本だ。詳細な解説をすればするほど、技術書は売れなくなっていく。千冊も売れればいいほうだろう。結果として、参考書を執筆して著者が得られるカネというのは数十万円だ。これでは経費を差し引くと給与所得者が確定申告に必要な雑所得の20万円すら下回る程度の利益しか得られない。そもそも技術書を執筆するためのまともなPCは数十万円するので、数年に渡って分割して経費にしなければならず、一台PCを買うだけで毎年本を出版しても数年は雑所得が確定申告が必要なレベルに達しない。

詳細な技術書を書くためには数年の時間がかかる。百万円台の収入では割に合わない。数年の執筆期間を維持するためには一千万円台の収入が必要だが、それには10万冊規模の売上が必要になる。日本で10万冊売れた技術書というのは、プログラマーたるもの読んだことがなければモグリのそしりを免れないような伝説的な本になるだろう。

ちなみに、100万冊売れた技術書は日本の全プログラマーが必携必読の書であり、このブログを読む読者は全員、手の届く範囲にその本を置いているような本になるはずだ。

さらに桁を上げるとどうなるのか。ありえないことだ。1000万冊売れる技術書などというものは存在するはずがない。それでもあえてそのような状況を発生させる条件を考えるとするならば、1000万冊売れた技術書の著者は新興宗教の開祖であり国内に何百万人もの信者を抱え、サイバークライムを救済されシリコンヘブンに行くためには免罪符として自著を購入しなければならない教義を説いているはずだ。

それにしても考えてみれば規模が小さい。現代の商業的な一般の書籍の流通に乗り、一般的な書店に並ぶ技術書の大半は千冊売れる程度なのだ。もはやコミケ以下だ。これでは技術書の執筆者は技術書を執筆するだけでは食べていけない。その結果、いま技術書を書いて生計を立てているような執筆者はいない。かの結城浩ですら、今は何をやっているかというと数学ラノベを書いている。

昔はこうではなかった。現代の感覚ではにわかに信じられないことであるが、昔は技術書を執筆するだけで生計を立てているプロの執筆者がいたと聞いている。一体どうしたらそんなことが可能になるのか。本の値段は何十年も変わっていない。むしろ最近のほうが安くなっている。一冊あたりの著者の印税も最近は安くなっているが、桁違いというほどではない。つまり昔は大抵の技術書が1万冊単位で売れていたということだ。事実、そうであったらしい。

昔は技術書が多く売れていた理由は、技術書が相対的に安かったからだ。今はインターネットの通信費用が限りないほど安価になっている。もはや日本では水と電気とインターネットは無料だと言ってもいい。紙の書籍は相対的に高い。しかし、昔は違った。通信費用は青天井に高かった。インターネットに接続するというのは、ISPの提供する基地局にモデムを介して電話をかけるということだった。そしてISPの基地局は都合よく同一市内の20km以内の場所に存在してくれたりはしない。帯域は本当に狭かった。当時の最後の時代の最高のモデムが56Kbpsだ。そもそも56Kbpsのカタログスペックがフルに出たりなどしない。たったの1MBをダウンロードするために何分もかかる、電話代は数百円かかるだろう。それを考えると、数千円で買える技術書が相対的に安くて売れるのは当然だ。

通信費が高いために、インターネット上にはそれほど情報がなかった事情もある。

現代ではインターネット上に情報が豊富にある上、最新の情報はインターネット上にしかない。本の執筆には時間がかかり、物理的に印刷して書店に並ぶには更に時間がかかる。しかも、今の技術の一次情報はすべて英語だ。すると、著者が英語を読んだ上で日本語で書くというオーバーヘッドもある。紙の本は出版された時点ですでに時代遅れなのだ。

さて、表題の本に戻ろう。今回クラウドファンディングで400万円を集めているわけだが、これはまだ低い。もう一つ桁が上がらなければ執筆に数年かかるような技術書は出せない。ただ、今回クラウドファンディングをしたことで圧倒的な宣伝効果を得たはずで、金銭以外の利益はあったはずだ。

不思議な時代だ。カネを払って宣伝をするのではなく、カネをもらって宣伝をするとは。結局、市場が小さすぎるのが悪い。

技術書の未来はどうなるのだろうか。私は今の傾向が続けば、もはや技術書などというものは滅びると思っている。そうなればプログラマーは皆日本語を捨てて余計なオーバーヘッドが排除されるので、長期的にはいいはずなのだが。

2018-07-04

C++17をすでに現場で使っているというキャディ株式会社に話を聞いてきた

CTOが「日本のC++のトップ人材の過半数が所属するイカれた会社にする」という宣言をした会社がある。なんとも壮大な話だ。C++プログラマーの業種は多岐にわたっているので、文字通りに考えると、そのような会社は自動車や旅客機の製造業であり、防衛庁の入札に参加する受注業者であり、OSや独自のプロセッサーを開発するためC++コンパイラー開発者も雇い、さらにはゲームもブラウザーも検索エンジンもクラウドホスティングもと挙げ続ければきりがないほど多方面に展開する大企業である。おそらくすでに名の知れた有名なIT系の大企業をほとんど買収すればそのような状態にはなるのではないかと思うが、金がいくらあっても足りない。

それはともかく、すでに現場でC++17を使っているという。

C++17は2017年に出たばかりの規格で、まだGCCもClangもコア言語はともかくライブラリーまでは完全に実装し終えてない状況だ。そのような状況で今C++17を使えるということは、最新の安定版のGCCやClangを本番環境で使える会社ということだ。果たして何をしているのか。

というわけで、その会社、「キャディ株式会社」に話を聞きに行った。

https://caddi.jp/: 板金加工なら【キャディ株式会社】―即日見積、5日納品、全国配送

Webサイトを見ると、板金加工をする会社だという。これだけではまだC++を使う理由がわからない。

話を聞いてみるとこうだ。

小規模な板金加工の受注生産というのは、小規模ないわゆる町工場が行っている。これまで板金加工をするには、町工場と直接交渉する必要があった。この顧客と町工場の間の交渉には、これまでほとんど技術革新がなかった。キャディはこの顧客と町工場の間に交渉に技術革新をもたらす、いわば仲介業か一次請けのような役割を果たす。

顧客は加工したいモデルデータをキャディのWebサイトからアップロードする。キャディはモデルデータを処理し、加工に必要な費用を見積もって表示する。この見積もりは一瞬で行われる。顧客が発注するとキャディは提携先の町工場に加工を依頼し、完成品を顧客に引き渡す。

顧客の送信したモデルデータから加工費用を一瞬で見積もるために、モデルデータの処理が必要だ。この処理にC++を使っている。

なるほど、C++を使う理由はわかった。ではどうやってこの比較的早い段階にC++17を使うことができるのか。その理由は簡単だった。規模の小さい新興企業だからだ。

現時点で従業員10人超、プログラマーが5人。そのような小規模な開発だからこそ可能になるのだろう。

大企業であればプログラマーとは別に専門のインフラ部署があり、インフラ屋はプログラマーとは少し違う目標を持っている。システムの安定性だ。新しすぎるソフトウェアは問題を引き起こす可能性がある。既存のソフトウェアに問題があるとしても、既知のものであり十分に情報があるので対処可能であるが、新しいソフトウェアの新しい問題は情報も少なく対処も難しい。この結果、インフラ屋はソフトウェアのアップデートに対して保守的になる。特にGNU/Linuxであればとても重要なC++コンパイラーであるGCCにはとても慎重になる。なぜならばGCCは他のほとんどのソフトウェアをコンパイルする重要なソフトウェアなのだから、GCCに問題があればシステムの全てに問題があることになる。

その結果、RHELのようなC++コンパイラーのアップデートが信じられないほどに保守的で時代遅れのディストロが使われる。

プログラマーが数人ですべてをやるような場合、この問題はない。

また、既存のコードが存在しないのも大きいのだろう。既存のコードが存在する場合、新しいコンパイラーによって不具合が修正され、その不具合に依存していたコードが壊れることがあるので、なかなかコンパイラーのバージョンを上げられない問題がある。

C++17をすでに現場で使っている話を聞くと、なんと私が過去に最新のClangを使っていて遭遇した問題に、同じく遭遇していた。

Clangは一時期、glibcのxlocale.hに依存していたことがある。これは非標準のglibcの独自ヘッダーでかなり昔からdeprecated扱いであり、最近削除された。

ディストロのパッケージにある安定版のClangを使いたい場合、私は空のxlocale.hを用意していた。パッケージ管理されたClangのヘッダーファイルを手動で書き換えるよりマシだ。

最新のClangでは修正されている。

Clangはvirtualデストラクターのある基本クラスをvirtual private派生で間接的に持っていた場合、デストラクターのアクセス指定を正しく判断できないregressionがある。Clang 3.3までは正しい挙動だったのだが、3.4から壊れてしまった。

30916 – If a class has indirect private virtual base with non-trivial public destructor, a class cannot access virtual base's destructor.

もう一年以上前にバグは報告してみたが、まだ修正されていないどころか何の反応もない。

こうして考えてみると、最新のC++コンパイラーには不具合も多い。既存の膨大なコードを修正するコストはかなり高い。常に最新のC++コンパイラーを使うのも茨の道だ。しかし、古いコンパイラーを使うということはこれ以上に莫大な既知の規格違反の不具合に対処する不思議なコードを書かなければならなくなるわけで茨の道であることに変わりはない。

ところで、このキャディ株式会社であるが、C++のプログラマーを随時募集しているらしい。応募方法はウェブサイトに記載されているメールアドレスに連絡してほしいとのことだ。

https://caddi.jp/: 板金加工なら【キャディ株式会社】―即日見積、5日納品、全国配送

2018-06-27

プログラミング入門書の執筆という手探りの活動

ここ最近、まともにブログを書けていない。最新のC++の提案も追えていない。それもこれも、C++によるプログラミングの入門書を書いているためだ。

およそプログラミングが個人でもできるようになって何十年もたとうとしているのだから、いい加減にプログラミングの入門書を書くお作法が成立しても良さそうなものだが、そういった定石は一向に確立されていない。名著と呼ばれる入門書は何冊もあるが、どれもその時代に特化した記述をしていて、その構成を模倣しても現代の入門書としては不適切だ。

結果として、入門書の執筆は自分の感性を信じつつ手探りで書き進めることになる。

よくC++の教育において批判されるのは、ポインターや配列といった低級な要素を最初に教える時代錯誤な点だ。たしかに、現代のC++はポインターや配列を使わなくても書ける。しかし、アドレスやメモリ上の連続したオブジェクトといった概念を理解しないまま優秀なコードが書けるだろうか。ポインターはアドレスを扱うには文法上の罠が多く、配列もメモリ上の連続したオブジェクトを扱うには文法上の罠が多い。

今書いているC++の入門書では、ポインターも配列も教えずに、vectorとイテレーターを教えている。しかし、コンテナーのカテゴリーやイテレーターのカテゴリーについては教えていないので、vectorとランダムアクセスイテレーターを前提にした記述になってしまう。

本当はコンテナーのカテゴリーやイテレーターのカテゴリーについて網羅的に教えたいのだが、そうすると具体的なコードがなく抽象的な分類とサポートされる操作といった文章が延々と続くことになってしまう。入門書では直接的なコードがすぐに書けるほうがよいと判断したのでvectorと実質ランダムアクセスイテレーターだけを教えているが、どうにも釈然としない思いがつのる。

プログラミングの入門書の冒頭では、どのようにしてコードを実行するかについて説明するものだ。既存の毎年改訂版が出るような使い捨ての入門書では、この説明のために、例えばVisual Studioのインストール方法の解説からはじめる。しかもご丁寧にいちいちスクリーンショットを載せ、ここのボタンをクリックしてなどといった本当に何のためにあるのかわからない解説が続く。

私が書いている入門書では、そのようなスクリーンショットは一切載せない方針にした。さらに、今年出たばかりの新しいツールに依存してしまうと、数年後に時代遅れになって使えなくなってしまう可能性が高いので、20年前に持っていっても使えるような安定したツールだけを使うことにした。その結果、使うツールはbashとGCCとGNU Makeになった。20年前から変わらないビルドシステムは、おそらく20年後もこのまま使えるはずだが、印刷される書物としてタブ文字と空白文字を区別するように説明するのはつらい。

今書いている入門書はあらゆることが手探りで進められている。例えば変数の宣言方法は以下のとおりだ。

// 整数
auto x = 0 ;
// 浮動小数点数
auto y = 0.0 ;
// 文字列
auto z = "hello"s ;

変数をいきなりこのような方法で教えるC++の入門書は今まで読んだことがないが、思うに最近の言語は強い静的型付けがないか、強い静的な型推論がある言語ばかりで、このような変数の書き方が自然になってきているので、これでよいだろう。

この調子で、最初に教える関数も以下のようになった。


auto plus = []( auto x, auto y ) { return x + y ; } ;

C++では、厳密にはこれは関数ではなくてラムダ式なのだが、こう書くことによって型を意識しないですむ。

ラムダ式を最初に教えることで、関数を渡す関数も自然に教えられるようになった。


int main()
{
    auto for_each = []( auto first, auto last, auto f )
    {
        for ( auto iter = first ; iter != last ; ++iter )
        {
            f( *iter ) ;
        }
    } ;

    std::vector<int> v = {1,2,3,4,5} ;

    for_each( std::begin(v), std::end(v),
        []( auto value ) { std::cout << value ; } ) ;
}

実際、std::for_eachは概ねこのような実装になっているのだと教えている。もちろん、これは本当のstd::for_eachの実装ではないし関数でもないので、厳密には違うが、初心者ならばこの説明でいいだろうと妥協している。

さらに一歩を踏み込んで、vectorの初期化を以下のようにできるのだが、おそらく混乱するだろうからまだやめている。これはC++17で採用されたdeduction guideによるものだ。


// std::vector<int>と同じ
std::vector v = {1,2,3,4,5} ;

今、ようやくアルゴリズムまで進んだのだが、今までに教えたことしか使っていない結果、関数はラムダ式で、コンテナーはvectorしか教えておらず、イテレーターはランダムアクセスイテレーターで、クラスはまだ教えておらず、テンプレートも当然教えていない。lvalueリファレンスだけは無理やり教えたがCV qualifiersは教えていない。

この状態で一体どこまで教えればいいのだろうか。C++を本格的に使うには、当然既存のC++のコードも読む必要があるだろうから、ポインターや配列を理解しなければならず、クラスやテンプレートも学ぶ必要がある。動的メモリ確保も必要だ。しかしこれらの概念を網羅的に解説するのはあまりにも抽象的すぎて、今想定している入門書では難しい。

今書いている入門書は本当に読者に想定していることが少ないので、C++のビルド方法からはじめ、エラーメッセージの読み方も解説したし、gdbの簡単な使い方も解説したい。

それにしても、今はC++を学ぶ対象読者の想定が難しい。一昔前ならばC言語をすでに学び終えた人間を想定すればよかったのだが、今はJavaScriptとかPythonかRubyぐらいしか触ったことのないプログラマーが増えている。彼らはコンパイルしてリンクして実行という仕組みに触れたことがない。

さらに、一昔前ならば想定することができなかった競技プログラマーという人種がいる。彼らは数学力は凄まじいがプログラミング言語には大して執着がなく、必要な計算を最小限のコードで実現できればそれでいいというとても割り切った使い方をする。プログラミング言語の文法をほとんど理解していないのに問題を解くコードは書けるというよくわからない人種だ。

そして入門書は浅く簡略化した解説を続けながらアルゴリズムまで来た。

この後はgdbの使い方、クラス、テンプレート、ポインター、動的メモリ確保、派生クラスあたりの順番で書こうかと思っている。C++の機能の依存関係の解決が辛い。すでに教えている機能だけを使う縛りを入れているので、早く機能を教えないといつまでも簡略化した説明を続けるハメになるが、いきなりポインターを教えても実感が沸かないだろうから、ポインターは相当後になる。

2018-06-14

xkcd: お客様特典

xkcd: Customer Rewards

23ドル3セントになります。

ところで、あなたの本名を教えていただけるのならば24セントお支払いたします。家族構成を教えていただけるのであれば35セント、電話番号に79セント、あなたのスマフォをこの場で貸していただいてあなたのFacebookの投稿一覧を確認させてもらえるのであれば1ドル20セントお支払します。

ポイントカードと特典は、独立した取引として考えた場合、とても奇妙なものになる。

title="うちの製品をSNSに投稿していただけるのであれば1ドル47セント、グループチャットで毎回話題に持ち出すのであれば2ドル5セント、運転中にうちの広告を通過した場合乗員一人に付き11セントお支払します。"

そういえばレシートを1枚10円で買い取るサービスが流行っているようだ。

2018-06-12

coinhiveが不正であるというナンセンスについて

coinhiveの設置者が不正指令電磁的記録取得・保管罪で略式起訴を受けたので正式に裁判して争う発表をした。

仮想通貨マイニング(Coinhive)で家宅捜索を受けた話 - Webを楽しもう「ドークツ」

高木浩光@自宅の日記 - 懸念されていた濫用がついに始まった刑法19章の2「不正指令電磁的記録に関する罪」

6月10日の高木宏光の記事では具体性がなかったのでよくわからなかったのだが、こうして具体例を目にしてみるとこの件がとてもひどいことがわかる。

裁判は多少のカネと時間がかかるがそれほど労力はかからない。数カ月に一度、提出した書類道理の陳述するという儀式をするだけのものだ。みんなもっと積極的に裁判をすべきだ。

法律の解釈は裁判をして判例を作ることで成り立っているので、おかしいと思った法律解釈には積極的に裁判をしないとどんどん悪い判例が積もっていく。

それはそれとしてcoinhiveは嫌いなので広告と同じくブラウザー拡張でブロックするべきだ。

2018-05-31

江添ボドゲ会@6月10日

下記のごとく毎月定例の江添ボドゲ会を開催します。

江添ボドゲ会@6月10日 - connpass

2018-05-29

世の中にはプログラミングを理解できない人間が存在する

現在、C++によるプログラミングの入門書を書いているので、初心者のプログラミングの学習過程にとても興味がある。私自身も初心者の気持ちを取り戻すためにHaskellを学んでみた。最初の数日は頭が痛くなるほど難しかったが、そこを過ぎてみれば後は楽になってしまった。結局、初心者の気持ちはあまりわからなかった。結局、プログラミングの基礎はすでに学んでしまっているので、

先日、FizzBuzzがわからないから教えてくれという知人がいたので、これは初心者の気持ちを知るいい機会と話を聞いてみたところ、想像を絶する世界が見えてきた。

まずこれが動かないと悩んでいたコードだ。


for ( int i = 0 ; i <= 100 ; i++ )
{
}
else if ( i % 15 == 0 )
{
    Debug.log("FizzBuzz") ;
}
else if ( i % 3 == 0 )
{
    Debug.log("Fizz") ;
}
else if ( i % 5 == 0 )
{
    Debug.log("Buzz") ;
}
else
{
    Debug.log(i) ;
}

一見するとそれらしいソースコードのようにみえるが、そもそも文法が間違っている。文法が間違っている箇所を指差しても納得しない。for文の文法を説明しようとするが聞く耳を持たない。「これが間違っているなら参考にしている教科書も間違っている」との一点張りで誤りが存在していることを頑なに認めない。参考にしているらしいスライド資料にのっているコード例と比較させても間違いの箇所を判断できない。for文の文法の説明をもう一度試みるがやはり聞く耳を持たない。

そしてソースコードの見た目を適当に書き換えてなんとか問題を「修正」しようと試みる。私はいつシェイクスピアの名作が出来上がるだろうかと考えながらその様子を見守っていた。

ややあって、奇跡的にソースコードが適切な形に「修正」された。しかし出力は期待通りにならない。当然だ。なぜならこれはUnityで、使っているのはデバッグログ用の機能であって、重複は省かれるからだ。出力は、1, 2, "Fizz"というメッセージが何件, 4, "Buzz"というメッセージが何件, 7, 8...と続く

そもそも基礎的なプログラミングの知識が十分ではないのだから、Unityはやめてもっと罠の少ないCLI環境でプログラミングの基礎を学ぶべきだと諭しても、「Unityは私がやりたいことを実現できる環境であり私のモチベ維持のために重要であるからUnityでやる」といって改めようとしない。

これは一体どうすればいいのだろう。こういう人間は教育不可能だ。この人物の経歴を見るに、どうもそれらしく見えるモックアップをでっち上げてきたアート系の人間のようだ。本人は今の時代は科学とアートは同じものでありアートを融合することでユーザービリティを考慮したUIが云々などと、まるでピタゴラス派のようなことを言う。世界は人間にとって美しい数字とか法則で定義されるべきであり、定義が観測結果に従わないとしても定義は正しいと主張したのがピタゴラス派だ。アートに引きこもっているならそれでいいのだが、それは科学ではない。コンパイラーのソースコードの解釈はこの自然界には珍しいことに冪等性を持っているのだから、見た目をでっち上げるのではなくて本質を理解すべきなのだ。たとえその本質が自分の美学に合わなかったとしてもだ。私は本棚にあったアラン・ソーカルの著書、知の欺瞞を手に取らせてみたが、あまり興味は示さなかったようだ。

こういう人間によって書かれたソースコードは一見もっともらしく見えるが、文法違反の間違ったコードとなる。どこかからか発見してきたコードをコピペしてツギハギしてそれらしい見た目のソースコードをでっち上げる。人間相手であれば、いかにも主題について理解したかのようにもっともらしくでっち上げた小論文を書いて読ませれば筆者は主題を理解していると読者を騙すことは可能だが、ことコンパイラーが相手では文法違反のソースコードを騙すことなどできない。

思うに、先天的に、あるいは幼少期の教育の結果、プログラミングに向かない学習方法に最適化されてしまった人間がいるのではないだろうか。物事の本質を完全に理解するにはコストがかかる。しかし、不完全な理解だがそれらしいものをでっち上げるにはコストがかからない。そして、人間には、それらしくでっち上げられた偽物と、本質を理解した上で作られた本物を判別するのが難しい。一方コンピューターは違う。コンパイラーはソースコードがいかに本物のソースコードらしい見た目をしていようとも、文法違反のソースコードを判別できる。コストを書けずに結果を出すためにそれらしくでっち上げる学習方法に最適化されてしまった人間は、コンパイラーに対して、それらしくでっち上げられたソースコードを食わせてコンパイラーが騙されてくれることを期待する。しかしコンピューターは騙されない。そもそも騙しようがない。コンパイラーは定義済みの規則に則って判断するだけで騙すという概念すらないのだから。

2018-05-17

ポルノ本意制の通貨が登場したことにより今後予想される問題について

ポルノ動画サイトの最大手であるポルノハブが仮想通貨Vergeによる支払いを受け付けているそうだ。

世界最大のポルノサイトが仮想通貨「verge」に対応、アクセスしてみるとびっくり! ポルノ業界が急激に進化中!

これはとても面白い事象である。というのも、この通貨はポルノと交換できることがポルノハブによって保証されているわけだ。すなわち、これは金本位制ならぬポルノ本位制である。しかもこの話は単なる空想に終わらない。ポルノハブは実際にこの通貨とポルノの交換を行っているわけで実態がある。ここにポルノ本位制の通貨が登場した。

ポルノ本位制の通貨が存在する社会はどのように変革していくのか、ポルノ本意制の通貨を使うときには何に気をつければよいのか。我々人類は通貨と経済学について長い歴史があるので、歴史から学ぶことで今後の動向は予測できる。本記事ではポルノ本位制の通貨がもたらすシュールな世界を紹介しよう。

ある通貨はポルノと交換できることが保証されているとして、一体どのようなポルノと交換できるのだろうか。ポルノはどのようなものであってもポルノであり、したがってポルノとしての価値を持つはずだ。質の高いポルノを生産するのにはコストがかかる。すると、世の中には質の悪い製造が容易なポルノが量産されるだろう。通貨と交換品の価値に差が生じた場合、人々は通貨と交換するポルノには質の悪いポルノを使い、質の良いポルノは貯蓄するようになる。これを「悪ポルノは良ポルノを駆逐する」といい、グレシャムの法則とも呼ばれている。

経済学的にポルノの価値を考えると興味深い事情がある。ポルノの価値はまだ誰も見たことのない市場に出回っていない新作ほど高い。みんな見たような市場に出回りすぎたポルノは価値が低い。これを考えると、ポルノは金のように価値が安定しておらず、消費財である。しかし金の生産量は簡単に増やせないが、ポルノの生産量は裸の人間とカメラさえあればいくらでも生産できる。しかも一人の人間に複数のカメラを使うことで並列生産も可能だ。中には車とドラゴンをポルノだとみなす人もいるが、ドラゴンの用意はやや難しい。最近は地図上にもドラゴンの住まう地と書かれる土地が少なくなったからだ。

ポルノ本意制の社会では、実経済に出回っている通貨がいつポルノとの交換を要求されるかわからない。そこで、銀行は十分な量の価値の高い未公開ポルノを戦略的に備蓄しておく。これを準備ポルノという。

なぜ実経済が存在するポルノより多い通貨を動かすようになるのだろうか。それは借金の存在のためだ。まだポルノを所有していない人間が、将来ポルノを所有する信用によって通貨を借りる。その通貨でポルノを生産し、借金を返す。このとき、生産したポルノによって借金以上の価値が生まれれば得をする。ところで、借金をしたときまだポルノは世の中に存在していなかったわけだ。しかし借金をしなければポルノは生産されなかった。したがって、実経済では常に準備ポルノ以上の通貨が動いているのだ。

現実には、市場に出回る通貨すべてを一斉に換ポルノしたときの需要を満たすほどの準備ポルノを用意することはできないだろう。皆が一斉に通貨とポルノ交換、すなわち換ポルノを要求したとき、取り付け騒ぎが起き市場が混乱する。このような取り付け騒ぎはめったに起こらないが、たまに些細な噂が拡大解釈されて発生することがある。例えば女子高生が何気なくつぶやいた、「最近ポルノハブ危ないんだって」という言葉からポルノの取り付け騒ぎが発生し、準備ポルノの少なかった弱小ポルノサイトが閉鎖に追い込まれることは十分にあるだろう。そのような自体に陥った場合、まず自殺したと噂される理事長自ら生存を主張し、巨大スクリーンでポルノを映すことにより準備ポルノは十分にあることをアピールすべきだ。

不況時には、ポルノが十分に国内に供給されない。このとき、国内にすらポルノ供給が足りていないのに海外にポルノを輸出するのはけしからんという極めて素朴で単純な考え方が国民に芽生え、そのような狭い思想の政治家が当選する。結果として、国家はお互いにポルノ輸出を禁ずるようになり、各国が経済的に鎖国し始める。

こうしたことから、ポルノ本意制はいずれ破綻し、廃止しなければならなくなるだろう。どうやって廃止するのかを歴史に学んで今から対策しておこう。国家は通貨とポルノの法定為替を一方的に定め、国民の所有するポルノ財産をすべて法定為替で強制的に買い上げるかもしれない。

そして、今と同じようにポルノと通貨は変動為替に移行し、取引所に直結したアルゴリズムトレード勢がマイクロ秒単位でポルノ価値を判断して先物取引をするようになるだろう。

他にも面白い思考実験として、フィクションの世界では水本位制がある。これはFalloutというゲームの世界の設定だ。全面核戦争の後に清潔な飲料水が貴重になり水が価値になった。しかし水を持ち運ぶのは手間なので、ある有力な水商人が水とボトルキャップを交換するようになった。なぜボトルキャップなのかと言うと、もはやボトルキャップを製造する技術や設備は存在しないからだ。つまり、ボトルキャップは偽造が実質不可能で、全面核戦争前に製造されたものしか残っていない。偽造が不可能であれば貨幣として使うには十分だ。

2018-05-14

OpenBSD、1985年に追加されたIntelの最新の誇大広告された機能を使わないことにより脆弱性を華麗に回避

“We didn't chase the fad of using every Intel CPU feature” | Hacker News

'Re: CVE-2018-8897' - MARC

前回の記事であるIntelの古いマニュアルを誤読したために生じた脆弱性では、IntelのCPUがスタック切り替えるためにss/spレジスターをアトミックに更新する汚いハックとして、ssレジスターが変更された直後の1命令は割り込みが遅延される古い仕様があるが、多くのOSはこの古い仕様を把握していなかったため、ssレジスターを変更した直後の1命令でカーネルモードに入り、かつハードウェアブレイクポイントが設定されたことにより割り込みを起こせば、カーネルモードに入った直後にカーネルのコードを1命令たりとも実行していない状況でカーネルモードとしてユーザーの割り込みが実行される脆弱性を引き起こしていた。

さて、各OSが対応に追われるなか、セキュリティに万全の体制を取ることで定評のあるOpenBSDでは特に何事もなくのほほんとしているので、MLにこのことについて質問をするものがいた。

OpenBSDが影響を受けないという理由について教えてほしいんですけど?

バカな質問ですみませんが、このFreeBSDもこの問題に引っかかっているのに、なぜOpenBSDは平気なのか不思議です。

事前に把握してたんですか?

昨日、一面記事になったような大ニュースになぜOpenBSDは引っかかっていなかったのか気になります。

これに対するTheo De Raadtの返事。

Intelの誇大広告まみれのCPU機能を全部追いかけるようなマネはしていないんでな。

We didn't chase the fad of using every Intel cpu feature.

強すぎる。

この機能というのはi386から追加されたハードウェアブレイクポイント機能のことだ。なんとOpenBSDではユーザースペースからx86のハードウェアブレイクポイント機能の使用を許可していない。ではgdbのようなユーザースペースのデバッガーはどうやってブレイクポイントを実装しているのかと言うと、古き良きソフトウェア実装を用いている。ブレイクポイントを仕掛けたい部分のコードを割り込み命令(int 3とか)とか無効命令(ゼロ除算)で置き換えておき、例外割り込みをブレイクポイントを仕掛けたい場所で発生させることによる移植性の高いソフトウェア実装だ。

ちなみに、IntelのCPUがハードウェアブレイクポイント機能を実装したのは1985年のi386にまで遡ることができる。

結果として、OpenBSDは今回の主要なOSが軒並み影響を受けた問題に対して何の影響も受けていないので、結果的に正しかったと言えるが、いやしかし凄まじい。OpenBSDのセキュリティにかける情熱を過小評価していた。

2018-05-11

Intelの古いマニュアルを誤読したために生じた脆弱性

Multiple OS Vendors Release Security Patches After Misinterpreting Intel Docs

Multiple OS Vendors Release Security Patches After Misinterpreting Intel Docs | Hacker News

8086でスタックを切り替えるには、ssレジスターとspレジスターを両方変更する必要がある。しかし、ssレジスターだけを変更してまだspレジスターを変更していないときに割り込みがかかると問題だ。そこで、8086は粋なはからいによって例外的にこの問題に対処した。ssレジスターを変更した直後の1命令では割り込みが発生しない。仮に割り込みが起きたとしても1命令を実行するまでは遅延される。

もし、ssレジスターを書き換えた直後の1命令でカーネルモードに入った場合、この粋なはからいが問題になる。カーネルモードに入ったあと、カーネルコードを1命令たりとも実行していない段階で割り込みが発生する可能性があるからだ。しかも実行はカーネルモードだ。

2018-05-08

glibcのabortマニュアルの中絶方針ジョークについて

Who controls glibc? [LWN.net]

「glibcのabortのマニュアルにはabort(終了)とabortion(中絶)をかけた中絶ジョークがあり、これはマニュアルとして有益ではなくて混乱の元なので削除するというパッチが提出され、受け入れられたが、RMSの反対により差し戻された」

これだけ読むとくだらない出来事のように思えるし、人によってはこのジョークの存在が好ましくないとか下品だと思うかもしれない。しかし、これは単に下品なジョークで片付けてよい問題ではない。実は音はもっと深いのだ。

まず、ジョークの内容は中絶ジョークではなく、中絶方針ジョークなのだ。

glibcのabortのマニュアルには以下の記載がある。

将来の変更警告:連邦検閲規制委員会に提案された方針によれば、この関数を呼び出すことができる可能性についての情報を我々が与えることが禁止されるかもしれない。我々はこれがプログラムを終了する適切な方法ではないと言わざるを得なくなるかもしれない。

問題の方針とは、メキシコシティポリシーと呼ばれているアメリカ合衆国では歴史の深いものだ。

Mexico City policy - Wikipedia

メキシコシティポリシーとはアメリカ合衆国政府の方針で外国籍のNGOがアメリカ政府から出資、健康補助、HIV補助、妊婦及び子供の補助を受ける場合「中絶の実施、並びに中絶を家族計画の方法として積極的に宣伝する」ことをしてはならない、というものだ。

これはアメリカ合衆国で中絶の違憲判決が出ていなかった時代から続く方針だ。歴史的に右翼である共和党はこの方針を肯定し、左翼である民主党は否定している。アメリカ合衆国における右翼とはキリスト教原理主義者を指し中絶は違法であるとの立場を取る。左翼はリベラルであり中絶は合法であるとの立場を取る。

メキシコシティポリシーの名前は1984年に共和党のロナルド・レーガン政権が名付けたものだ。これは1993年に民主党のビル・クリントン政権で撤回されたが、2001年に共和党のジョージ・W・ブッシュ政権で復活し、2009年に民主党のバラク・オバマ政権で撤回され、そして当然、2017年の共和党のドナルド・トランプ政権では復活した。

ちなみに、ブッシュ政権のときにメキシコシティポリシーの違憲性を問う訴訟で、アメリカ政府が外国籍のNGOを補助するときに中絶への立場を考慮することは違憲ではないという判決が出ている。

さて、話をglibcに戻そう。glibcというのはGNUであり自由ソフトウェア財団である。RMSが始めたGNUはその当初から左翼主義が全面的に出ており、ソフトウェア開発は政治活動だと考えている。その思想に基づけば、この20年前からマニュアルに存在する中絶方針ジョークは必要不可欠でありたやすく取り除いてはならないものである。

今回はRMSが強権を発動し、ジョークは残った。

この問題の背景事情を考えるに、私はこの中絶方針ジョークは残すべきであると思う。

2018-05-03

LLVMで5番目に貢献の多い開発者、LLVMの最近のSJW運動に反対して開発をやめると表明

One Of LLVM's Top Contributors Quits Development Over CoC, Outreach Program - Phoronix

[llvm-dev] I am leaving llvm

Rafael Avila de Espindolaは2006年からLLVMに対して4300以上もコミットした開発者で、現在LLVMの全Authorの中で第5位のコミット数を保有する開発者である。Rafaelは最近のLLVM Code of Conductと今年のアウトリーチプログラムへの参加を、「社会不正義」(Social Injustice)だと吐き捨ててLLVMの開発をやめる声明を出した。

LLVMのCode of Conductは以下の通り。

LLVM Community Code of Conduct — LLVM 7 documentation

  • 仲良く辛抱強くやれよ
  • 新参は歓迎しろよ
  • 迷惑かけんなよ
  • 尊敬しろよ
  • 言葉遣いには気をつけるのと、あと親切にしてやれよ

Code of Conductは、過去に様々な自由ソフトウェアコミュニティが取り入れて、その結果政治的な問題を引き起こしてきた歴史がある規約だ。そもそも存在自体が政治であるものを入れると純粋な技術から遠ざかり、些細な言葉遣いのような揚げ足取りの政治に終始するのは当然であると言えよう。

アウトリーチプログラムというのは現在コミュニティでマイノリティである属性を持った開発者を新規に確保するための優遇措置だ。属性というのは主に性別で、具体的には女性のことだ。しかしこれは純粋な技術力ではない性別のような条件で人を優遇するということであり、これはまさに性差別そのものである。これをやりだすと人物が純粋な技術力で評価されず、たまたまマイノリティの性や宗教や門地のような属性を持っていたというだけで優遇される。

私がさる理由はコミュニティの変化のためだ。現在のライセンス変更の議論は私がGCCの開発をしていた頃の自由ソフトウェア財団の政治を彷彿とさせるものがある。これだけではまだ去るほどの理由ではない。コードと同じように、LLVMはまだ最適なライセンスを選択しているし、コミュニティの変化というのがライセンスの変更だけであれば、まだ続けることもできた。

私が受け入れられないコミュニティの変化は社会不正義運動がはびこっていることだ。私がLLVMに参加したとき、誰も私の宗教や政治信条について疑問を呈するものはいなかった。我々は皆、良きコンパイラーフレームワークを作ることに注力していた。

ここ最近、Code of Conductやらが採用された。これによれば、コミュニティはすべての「政治信条」を歓迎するよう務めるとある。しかし、Code of Conductの存在に反対する政治信条を持つ者は歓迎できない。そして、カンファレンスに参加するにはCode of Conductへの同意が必要であるからして、私はもはや参加することができなくなった。

トドメの一撃は、LLVMがある団体と手を組んだことで、この団体は公に性別や門地による差別を行っている。これは私の倫理と真っ向から対立するものであり、私はこの手の輩と一緒くたにされないために、プロジェクトを去る必要がある。

RafaelのMLへの投稿は、最後に"So long, and thanks for all the bugs,"(さよなら、いままでバグをたくさんありがとう)と締めくくっている。銀河ヒッチハイクガイドへのリファレンスのようだ。

2018-04-23

C++入門書で再帰について解説しようとしたら思わぬ最適化できないコードに出くわした

C++入門書を書き始めて早数カ月、すでに文章量が「江添亮の詳説C++17」の半分近くに達しているが、まだようやくループを説明したところだ。

ループの章を一通り書き終えて、ついでに再帰によってループを実現する方法について軽く触れて章を閉じようと、以下のようなコードを書いた。

void hello()
{
    std::cout << "hello\n"s ;
    hello() ;
}

すると何故かsegmentation faultを起こすではないか。GCCでもClangでも同じ挙動になる。なぜC++コンパイラーはこの程度の末尾再帰を最適化できないのだろうか。

不思議に思って以下のコードも試すと、こちらは問題なく末尾再帰の最適化が行われる。

void hello()
{
    std::cout << "hello\n" ;
    hello() ;
}

違いは文字列だ。今回の入門書では、初心者に簡単にするために、文字列はすべてstd::stringを返すユーザー定義リテラルのoperator "" sを使っているのだ。これにより初心者は、"hello\n"sとかけばstd::stringとして使える。つまり、

auto s = "hello"s ;
s.size() ;

などと書ける。難しいことを一切考えなくてもよい。わたしの本が書き上がって出版されるまでにまだ1年はかかるだろうし、その頃にはC++17が普及している。C++17を使って初心者でも学びやすい記述をすることで、私のC++入門書は初心者にも優しい本になるだろう。そう考えていた矢先に何ということだ。

どうもstd::stringがあると末尾再帰の最適化が行われないらしい。しかしおかしい。一時オブジェクトの寿命はリファレンスにより寿命延長されない場合はfull-expressionの中までのはずだ。したがってこのコードはまだ末尾再帰のはずだ。再帰呼び出し後に何かする必要は何もないはずだ。

不思議に思って以下のコードを試してみたが、やはり末尾再帰の最適化はされていない。

void hello()
{
    {
        std::string s = "hello\n" ;
        std::cout << s ;
    }
    hello() ;
}

これなら一時オブジェクトでもないしブロックスコープを明示的に使っているし問題はないだろうと思ったが、なぜかコンパイラーは末尾再帰の最適化を諦めてしまう。

では関数で包んでしまうというのはどうか。

void hello()
{
    []{ std::cout << "hello\n"s ; }() ;
    hello() ;
}

これはうまくいった。関数で包んだ場合、コンパイラーは末尾再帰を最適化する。

コンパイラーの気持ちはよくわからない。

2018-04-18

2018-04でC++のドラフトに入った変更

C++のドラフトが更新されている。最新版はN4741だ。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4741.pdf

変更点はEditor's Reportに書いてある。

N4740: N4740 Editors' Report -- Programming Languages -- C++

今回入った主要な変更は以下の通り。

P0840R2: Language support for empty objects

[[no_unique_address]]属性の追加。

この属性は、クラスが状態を持たずクラスを表現するためにストレージを割り当てなくてもよいことを意味する。

クラスには、存在すること自体に意味があり、そのオブジェクトに特に意味はないクラスがある。


template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  Hash hasher;
  Pred pred;
  Allocator alloc;
  // ...
public:
  // ...
};

このようなコードで、HashやPredやAllocatorといったクラスが状態を持たないもののみを使用可能だと取り決めた場合、ストレージを割り当てる必要がない。しかし、このような基本クラスや非staticデータメンバーであっても、アドレス可能にするために最低でも1バイトはストレージを割り当てる必要がある。

[[no_unique_address]]はこのようなストレージの確保を必要としない、アドレスを取る必要がない型に使うことで、不必要なストレージの割当を回避することができる。


template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  [[no_unique_address]] Hash hasher;
  [[no_unique_address]] Pred pred;
  [[no_unique_address]] Allocator alloc;
  // ...
public:
  // ...
};

P0962R1: Relaxing the range-for loop customization point finding rules

range-based forはメンバー関数begin/endのいずれか片方を持っている場合は、ADLによるbegin/endの検索を行わない。しかし、たまたまクラスがbegin/endという名前の片方のメンバー関数だけを持っていた場合も、ADLによる検索が行われない。

range-base forはbegin/end両方のメンバー関数を持つ場合のみADLによる検索を行わないようにする変更。

当然の話だ。

[PDF] P0969R0: Allow structured bindings to accessible members

クラスを構造化束縛する場合、メンバーはpublicでなければならないとされている。


class Three
{
    int a, b, c ;
} ;

void f()
{
    Three t{1,2,3} ;
    auto [a,b,c] = t ; // エラー
}

しかしこれはおかしな話だ。というのも、アクセス指定というのは使った文脈が重要だからだ。


class Three
{
    int a, b, c ;
    friend void f() ;
public :
    Three( int a, int b, int c )
        : a(a), b(b), c(c) { }
} ;

void f()
{
    Three t{1,2,3} ;
    // エラー、friendなのに
    auto [a,b,c] = t ; 
}

構造化束縛でpublicなメンバーに限らず、アクセスできる場所ではアクセスできるようにする変更。

当然すぎる。

P0961R1: Relaxing the structured bindings customization point finding rules

構造化束縛でメンバー関数getが見つかったときに、テンプレートではない場合は、ADLで検索する機能。

これも当然だ。

P0634R3: Down with typename!

文脈上型であることが明らかな場所では依存名にtypenameを付けなくても良くする機能。

template < typename T >
using type = typename T::type ;

と書くかわりに、

template < typename T >
using type = T::type ;

と書ける。他にも様々な文脈上型しか書けない場所でtypenameを省略できる。

P0780R2: Pack expansion in lambda init-capture

ラムダ式の初期化キャプチャーの中でパック展開できる機能。

たとえば、パラメーターパックをstd::moveしつつパック展開して初期化キャプチャーするには以下のように書ける。

template < typename ... Types  >
void f( Types & ... args )
{
    [ ... args = std::move(args) ]
    (){ } ;
}

P0479R5: Proposed wording for likely and unlikely attributes (Revision 5)

分岐先の実行されやすさを指示できる[[likely]], [[unlikely]]属性の追加。

ある分岐先が実行されやすい時、あるいは実行されにくいときがコンパイル時にわかっているときは、その情報をコンパイラーにヒントとして伝えることで、コンパイラーは実行されやすいコードをよりキャッシュに乗りやすいホットな領域に配置したり、コード生成を工夫したりといった最適化ができる。


// めったに起こらないエラーの確認
if ( check_uncommon_error() )
{
    [[unlikely]] ;
    // エラー時の処理
}

// 必ず成功するはずの初歩的なチェック
if ( sanity_check() )
{
    [[likely] ;
    // 通常の処理
}

P0905R1: Symmetry for spaceship

比較演算子としてoperator <=>が追加されたが、"a <=> b"が合法であるならば、"b <=> a"も合法であり、かつその結果も自然なものになるように規定する変更。

[PDF] P0754R2: version

何もしないヘッダーファイル<version>の追加。このヘッダーファイルはコンパイラーによって定義される実装依存の定義済みマクロなどを定義ささせるのに使われる。そのような定義済みマクロを使うには、何らかの標準ヘッダーを#includeしなければならず、そのような軽量ヘッダーとして追加された。

P0355R7: Extending to Calendars and Time Zones

<chrono>にカレンダー機能を追加する。ユーザー定義リテラルによりコード中でも読みやすくなる。

int main()
{
    auto date = 2018y/April/18 ;

    // 2018-04-18
    std::cout << date << "\n" ;

    // 2018-04-19
    date += 1 ;
    std::cout << date << "\n" ;
    
    // 2018-03-25
    date -= 25 ;
    std::cout << date << "\n" ;
    
}

日付処理が簡単にできるようになる。

[PDF] P0122R7: span : bounds - safe views for sequences of objects

spanライブラリの追加。これは連続したストレージ上の配列を扱うストレージを所有しないライブラリだ。

ロシア、Telegramをブロックするために180万ものIPアドレスをブロック

Russia Bans 1.8 Million Amazon and Google IPs in Attempt to Block Telegram

ロシアはインスタントメッセージングサービスのTelegramをブロックするため、AmazonやGoogleの所有する約180万ものIPアドレスをブロックした。

以下がそのIPアドレスの範囲で、1835008個のIPアドレスになる。


52.58.0.0/15
18.196.0.0/15
18.194.0.0/15
18.184.0.0/15
35.156.0.0/14
35.192.0.0/12

Telegramの創始者は以下のような声明を出したそうだ。

Telegram: Contact @durov

過去24時間でTelegramはロシアのISPによってBANされた。理由は我々が暗号鍵をロシアの諜報機関に提出するのを拒んだためだ。我々にとってこれは容易い選択であった。我々は顧客に対し100%のプライバシーを約束しており、約束を守れぬのであればむしろ消えるべきであるからだ。」

BANにもかかわらず、ユーザーの利用率は極端に落ちていない。これはロシア人は政府の検閲に対抗するために日常的にVPNやプロクシーを使っているためである。また我々はサードパーティのクラウドプロクシーサービスを使うことで部分的にユーザーにサービスを提供し続けている。

ロシアのTelegramユーザーの皆さんの協力に感謝する。また政治的検閲に与しなかったApple, Google, Amazon, Microsoftにも感謝する。

ロシアはTelegramユーザーの7%を占めている。ロシア市場を失ったとしても、他の地域でのユーザーの増加がこの穴を数ヶ月以内に埋めるであろう。しかし、ロシアのユーザーにサービスを提供し続けることは個人的にも重要だ。

ロシアとその他の地域におけるインターネットの自由を守るために、私はsocks5プロクシーとVPNを提供する個人や団体にbitcoinを寄付することにした。私はこの運動のために今年数百万ドルを喜んで寄付するし、私に続く者が出てきてほしい。私はこれをデジタル抵抗軍を呼ぶ。電磁的自由とその進展に対する草の根活動だ。

一方、日本では出版社が両手を上げて、緊急避難によるIPアドレスのブロックに賛同している。日本もロシアや中国と同じ道を辿りつつある。隷属への道は近い。

2018-04-07

江添ボドゲ会@4月15日

connpass: 江添ボドゲ会@4月15日

江添ボドゲ会、今月は4月15日。

ゴールデンウィークあたりに鍋会もしたい。

2018-04-05

入門書の文章量が増える問題

C++17の参考書を書き終えた今、この世に必要なのはC++の入門書だ。そこでC++の入門書を苦しみながら書いているのだが、一つ問題がある。文章量が多いということだ。

今書いているC++の入門書は、まだ本の序盤までしか書いていない。C++のソースコードのコンパイルと実行方法、ビルドシステム、そしてようやく条件分岐を半分ぐらい書いた。後は付録としてプリプロセッサーを解説した。その程度だ。

しかし、wcで現行を単一のHTMLファイルに変換した結果を大雑把に計算すると、今書きかけのC++入門書が"2335 7876 178578"に対し、完成したC++17本が"8280 31208 639671"だ。まだ条件分岐までしか書いてないというのに少し分量が多くないだろうか。

考えてみると、文章量が多くなるのも無理はない話だ。初心者の気持ちに寄り添って書いている結果、「整数と浮動小数点数を演算すると結果は浮動小数点数になる」と書けば済む程度のところを、

  1. 整数と浮動小数点数を演算するとどうなるのだろうか?
  2. 確かめてみよう。
  3. ソースコード
  4. 実行結果
  5. なるほど、整数と浮動小数点数を演算すると浮動小数点数になることがわかる

などという冗長な書き方をしているためだ。これでは文章量が増えるのも当然だ。

しかし、冗長ではない書き方をするとなると、結果的にリファレンスマニュアルのような無味乾燥とした記述が続く。それで入門できる人間は、規格書とか私が昔書いたC++11/14コア言語を読めばC++を学べるはずだ。

とはいえ、文章量が多いとそれだけ読むのに労力がかかり、ただでさえ人間の脳に負担を強いる全く新しいプログラミング言語の習得に、長文を読むという追加の負担を強いることになる。

この問題をどうすればいいのだろう。Bjarne StroustrupのC++入門書があまりにも長大で鈍重で悪書の見本のような参考書であるとかつてあざ笑ったが、これは笑えない由々しき問題だ。このペースで書き続けると鈍器として凶器転用可能な重量を持つ入門書ができあがってしまう。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2018-03-24

vectordash: 暗号通貨採掘している奴らに暗号通貨採掘よりは歩合のよい報酬を払ってGPGPU計算を購入するGPU版AirBnBみたいなサービス

Rent out your GPU compute to AI researchers and make ~2x more than mining the most profitable cryptocurrency. : gpumining

Deep Learningを研究しているある苦学生は、AWSやGoogle CloudのようなクラウドでGPGPU計算を提供している高い利用料に頭を悩ませていた。そこで、GeForce GTX 1080Tiを複数枚使ってEthereumを採掘している友人の存在に気が付き、交渉して、Ethereumを採掘するよりも歩合のよい報酬を支払い、機械学習に必要なGPGPU計算を請け負ってもらうことにした。その対価はEthereumを掘るよりは高いが、AWSやGoogle Cloudよりはよっぽど安い。

望みのGPGPU計算を終えてめでたしめでたしの苦学生はふと思う。「まてよ、世の中の暗号通貨採掘しているやつは、AI研究者に計算力を売ったほうが歩合がいいんじゃないのか」と。

そのような小規模なGPGPU計算力を売買するインフラは存在していなかったので、学生は自分で作り上げた。Vectordashだ。

Vectordash: GPU instances for deep learning

仕組みとしてはGPGPU計算力の売り主のコンピューターで実行されるコンテナーに買い主がsshしてGPGPU計算をして対価を支払うというものだ。

要するに、GPGPUのAirBnBみたいなものだ。

面白い仕組みだ。暗号通貨の採掘に計算力を注ぎ込んでも暗号通貨を維持する以上の価値はない。しかしこの方法では、計算力を直接販売できるし、暗号通貨採掘の利益より高いのであれば、売り手も買い手もWin-Winではないか。AWSやGoogle Cloudより安いとあればなおのことよい。

もちろん、すでに大勢の人間が指摘しているように、信頼という問題点がある。

売り主は本当に本物の計算力を提供しているのだろうか。特にGPGPU計算を売るというのが難しい。売り主に悪意があれば、カーネルに手を加え、GeForce GTX 1080を複数枚用意していると見せかけ、実際には何も計算せず、ランダムな結果を返すことができてしまう。結果は信頼できない。

たとえ売り主に悪意がないとしても、ハードウェアは故障する。コモディティハードウェアの信頼性は高くない。もしGPUが故障して間違った計算を行うが、見かけ上正常に動作しているように見える場合、結果は信頼できない。

計算力の売り主が信頼できない状態で計算結果の信頼性を担保したい場合、複数の売り主に同一の決定的(deterministic)な計算を依頼し、結果が同一であるかどうかを比較することで信頼度を上げることができる。しかし、そうすると利用料は数倍になり、AWSやGoogle Cloudに対して安いという魅力がなくなる。それに、完全に決定的(deterministic)な計算だけを扱うのも難しい。

買い主の悪意はどうだろうか。GPUはDMAできる。すると、買い主はDMAにより仮想化の檻を脱獄し、あまつさえルート権限を取得し、売り主のコンピューターをBOTネットワークの一部とするだろう。GPUに対するセキュアな仮想化技術はまだ発展途上だ。そして、セキュリティを担保するとパフォーマンスに影響を与えるだろう。

個人が計算力を提供する分散コンピューティングというのは前例のない話ではない。たとえばSETI@homeは宇宙からの観測データを有志が計算力を提供することにより知的な宇宙人の存在を発見しようという目的をもった分散コンピューティングだ。Folding@homeはタンパク質の折りたたみ構造を有志が計算力を提供することによって様々な疾患の治療に役立てようというものだ。

SETI@home

Folding@home

これらの既存の分散コンピューティングは、計算内容の提供者は固定で、参加はボランティアによるもので、しかも参加者に短期的な金銭による対価が支払われることはない。そのため、悪意ある計算力の提供者の存在や、計算内容に悪意があるリスクは低いと考えられる。

しかし、今回のvectordashとやらは、汎用的な計算力の売買を行うので、悪意の可能性は大いに考慮しなければならない。

問題はあるものの、暗号通貨に計算力と電力を注ぎ込むよりは、よほど人類にとって有益な計算力市場が出来上がるのではないか。

2018-03-19

2018 Jacksonville会議でC++のドラフト入りが決定した機能

2018 Jacksonville ISO C++ Committee Reddit Trip Report : cpp

なぜこのような情報をRedditで見なければならないのかという疑問はあるが、2018 Jacksonville会議の結果がRedditでまとめられている。

P0840R1: Language support for empty objects

[[no_unique_address]]属性が追加された。この属性はクラスの非staticサブオブジェクトがユニークなアドレスを必要としないとコンパイラーに支持するものだ。これによって、コンパイラーはそのサブオブジェクトにメモリレイアウト上でスペースを割り当てる必要がなくなるので、Empty Base Optimizationができる。

struct A { } ;
struct B { } ;
struct C { } ;

struct D
{
    [[no_unique_address]] A a ;
    [[no_unique_address]] B b ;
    [[no_unique_address]] C c ;
} ;

int main()
{
    // 1
    std::cout << sizeof(D) ;
}

例えばtraitsのようなクラスのサブオブジェクトとして持っておくのに使える。

template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  [[no_unique_address]] Hash hasher;
  [[no_unique_address]] Pred pred;
  [[no_unique_address]] Allocator alloc;
  Bucket *buckets;
  // ...
public:
  // ...
};

P0634R2: Down with typename!

文脈上、型しか書けない場所に書かれたものは型であるとみなすことにより、依存名にtypenameを記述しなくてもすむように制限緩和する提案。

依存名が型である場合はtypenameキーワードによって型であることを明示しなければならない。


// Tはこんな感じの型を想定
struct example
{
    using type = int ;
    static constexpr type value = 0 ; 
} ;

// 
template < typename T >
typename T::type f()
{
    typename T::type x = T::value ;
    using type = typename T::type ;
    std::vector< typename T::type > v 
    return x ;
}

このコードが以下の様に書けるようになる。


template < typename T >
// typenameはいらない
T::type f()
{
    // typenameが必要
    typename T::type x = T::value ;
    // typenameはいらない
    using type = T::type ;
    // typenameはいらない
    std::vector< T::type > v 
    return x ;
}

書きやすくなった。

P0479R4: Proposed wording for likely and unlikely attributes (Revision 4)

[[likely]]と[[unlikely]]の追加。この属性は文に書くことができる。この属性が書かれた文を含む実行パスの実行の期待度を示す。

例えば以下のようなコードがあるとして、


while ( true )
{
    // まれにしか起こらないエラーのチェック
    if ( check_rare_error_condition() ) {
        // 分岐1
        // エラーへの対処
    } else {
        // 分岐2
        // 通常の処理
    }
}

このコードでは、エラーが起こることはまれであり、したがって分岐1が実行される可能性は低い。コンパイラーがその情報を事前に知っていれば、コード生成の際に役立てることができる。


    if ( check_rare_error_condition() )
    {
        [[unlikely]] ;
        // エラーへの対処
    }

この機能は大抵のコンパイラーが独自拡張として様々な文法ですでに実装している。

[PDF] P0754R1: version

ヘッダーファイル<version>を追加。このヘッダーファイルは標準規格的には何も入っていない。実装依存のバージョン番号やリリース番号を示す定義済みマクロを提供するためのヘッダーファイルだ。

多くのC++コンパイラーが独自の定義済みマクロでコンパイラーのバージョンその他の情報を提供している。問題は、そのような定義済みマクロは、コンパイラーマジックによって定義されるのでもなければ、なんらかの標準ライブラリのヘッダーファイルを読み込まないと定義されない。

そこで、標準ライブラリの中でも特に軽量なヘッダーファイルである<ciso646>が慣習的に使われてきたが、今回、ciso646は実用的な機能を提供していないので廃止しようという議論が持ち上がった。そこで、このヘッダーファイル自体に意味はないが、コンパイラー独自の定義済みマクロのためだけに#includeしている既存のコードがたくさんあるという指摘が上がった。

そのため、その用法をサポートするための最も軽量なヘッダーファイルである<version>が提案され、追加された。

P0355R5: Extending <chrono> to Calendars and Time Zones

<chrono>にカレンダーライブラリの追加。

int main()
{
    auto date = 2017y/mar/18d ;
    // "2018-03-18"
    std::cout << date ;
}

カレンダー操作が型安全に行える。

[PDF] P0753R1: placeholder

osyncstream用のバッファーフラッシュの動作を制御するマニピュレーターの追加。

[PDF] P0122R6: placeholder

連続したストレージを所有しないまま配列として扱うspanライブラリの追加。提案段階ではarray_refとかarray_viewなども提案されていたが、最終的にspanになった。

P0780R1: Pack expansion in lambda init-capture

ラムダ式の初期化キャプチャーでパック展開ができるようになった。これにより可変長テンプレートを使った関数テンプレートでラムダ式にパラメーターパックをそれぞれムーブキャプチャーすることができるようになった。

template < typename ... Types  >
void f( Types ... args )
{
    [ args = std::move(args)... ](){} ;
}

ドラフトの変更以外としては、simd<T>がParallerism TS v2に入ったり、Reflection TS v2, Library Fundamentals TS v3が発行されたりした。

現在の観測を見てみると、モジュールがC++20に入るかは疑わしい。コンセプトとレンジのコアは入りそうだ。

colony(歯抜けを許すvector)やflat_map(ソート済みvectorのバイナリサーチ)はC++20に入ってほしい。他には、fixed_capacity_vector(サイズ固定vector)やring_span(リングバッファー)

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2018-03-16

自宅のメインPCのストレージが故障した

江添亮の詳説C++17本の発売の余韻に浸る暇もなくC++入門書を書いているが、これがなかなか面倒だ。というのも、C++を学ぶ前にまず、C++のソースファイルをコンパイルして実行する方法を学ばなければならないと考えたので、環境構築から書いている。

具体的にはmkdirでディレクトリを作りcdで移動してそこにvimでテキストファイルを作成しGCCでコンパイルして実行するがカレントディレクトリはPATHに含まれていないので./を忘れずにつけるようになどといった、誰でも書けるような本当に初歩的な内容を書いている。

はたしてこんな初歩的な内容が必要なのかと疑問に思うこともあるが、しかし初心者がどこでつまづくかわからない以上、すべて書くしかない。すでにプログラミングを学んでいて実用的なソフトウェアを書いている人間であっても、今やプログラミング環境は多種多様になっており、CLIでの操作経験がまったくないままプログラマーとしてやっている人間がいても不思議ではない。したがって、カレントディレクトリはPATHに含まれないとか、コンパイルやリンクといった概念の説明が必要になる。

話は変わるが、今朝自宅のメイン環境として使っているラップトップの調子がとても悪かった。まずブートせずにbusyboxのシェルを表示する。fsckを書けたところブートするようにはなったが、何やら極端に遅い。dmesgするとストレージへのアクセスでエラーが大量に出ている。どうやらストレージが壊れたようだ。幸い、データはサルベージできたし、プログラマーの当然の嗜みとして参考書はgitで管理しており、常に複数のストレージに入れるようにしてあるので問題はなかったが、メインPCが使えないのは困ったものだ。自宅にはゲーム専用の不自由な日本語IMEすら無効化しているWindows PCとゴミのようなタブレットしかない。このタブレットはAMDの超省電力の非力なCPUを使っており、かつGPUがLinuxカーネルで使えないのでこともあろうかLLVMpipeでグラフィック表示している最悪の環境だ。

メインで使っていたラップトップは15インチで4Kディスプレイを内蔵していて、かつnVidiaのGPUを積んでいないという稀有な存在だ。AMDのGPUを積んでいるらしいのだがなぜかUbuntuでは認識されず、Intel HD Graphicsだけで動いている。訳あり中古で買った格安品で、訳ありの理由は、内蔵ディスプレイの中央あたりに白い常時点灯の線があるというものだ。地味につらいが値段は安く、4Kディスプレイを内蔵しているnVidiaのGPUを積んでいないコンピューターだったのでだましだまし使っていたのであった。

ストレージはHDDにキャッシュ用のそれなりの容量のフラッシュメモリがついているという、少し前に流行ったハイブリットHDDだ。ストレージさえ交換すれば再び使えるようになるのではないかとも思うが、残念ながらNVMe M.2 SSDとは違い、おそらくはラップトップ用のSATA接続の2.5インチHDDであろうし、調べたところ分解手順が一般人の分解を想定していないほど面倒だ。

早く自宅のメインPCを調達して自宅で参考書を執筆できる環境を整えなければならない。しかし思ったのだが、これはC++17本の印税の突っ込みどころとして最適ではないか。雀の涙のような印税ではあるが、高スペックなラップトップを一台買えるぐらいの額はある。それに経費と相殺すれば雑所得が確定申告が必要な額である20万円を下回るのではないか。ただ、調べると10万円を超え、かつ1年以上使うコンピューターについては減価償却という概念が出てきて、耐用年数が4年だそうだ。ただ、どうせ印税の額は少ないので4分の1にしても20万円を下回るのは容易いように思われる。ただ、それが執筆専用に使われない場合は比率を考えないといけないのでそれも難しい。

経費と税金のややこしい話はともかく、自宅に執筆用のPCが必要なので、さっそく久しぶりにラップトップを物色したが、どうにも難しい。私がほしいのは、15インチで4Kディスプレイ内蔵でnVidiaのGPUを積んでいないラップトップだ。私の本の執筆には高性能なGPUはいらないし、nVidiaのGPUは不自由なバイナリブロブのカーネルモジュールを必要とする。しかし、世の中には12インチで他の条件を満たすものか、15インチでnVidiaのGPUを積んでいるものしかない。

そして、ここ1,2年ぐらい顕著なのが、3K解像度のディスプレイだ。3200x1800程度の解像度のラップトップが増えている。これはけしからんことだ。作業効率というのは眼球にどれだけ多くのピクセルを叩き込めるかで決まるものだ。1920x1200が1920x1080に駆逐されたときも失望したのだが、4Kディスプレイの劣化版がHiDPIを名乗っているのもけしからん。3Kは劣化。4Kディスプレイは最低限の基準だ。

まあ、実際の理由は、4Kディスプレイ内蔵のラップトップはバッテリー駆動時間が短いので、HiDPIを謳いつつ電力消費を下げるために3K内蔵ディスプレイが出てきたのだろうし、15インチ4KディスプレイにnVidiaのGPUを積んだラップトップしかないというのも、15インチで4Kディスプレイを内蔵したラップトップにはGPU性能の需要もあるからそういう製品ばかりになっているのだろう。15インチで4Kディスプレイ内蔵でGPU性能はいらないという私の需要は少数派なのだろう。

というわけで、候補はSystem76かPurismか、あるいはDellのXPSあたりになる。System76は3K解像度、Purismは解像度も1920x1080しかない。Dellは無難だが、やはり15インチにはnVidiaのGPUがあり、13インチは3Kディスプレイだ。

2018-03-14

git submoduleを含むレポジトリをGitHub Pagesで公開するときのsubmoduleのURLはhttpsでなければならない

江添亮の詳説C++17の出版記念の勉強会で使うスライド資料をGitHubにあげてGitHub Pagesで公開する作業をしていた。

歌舞伎座.tech 番外編「江添亮の詳説C++17」出版記念 - connpass

私はスライド資料の作成は、markdownで書き、pandocでreveal.js形式に変換し、reveal.jsでスライド形式で表示させている。いつもならばreveal.jsはリリース版のtarを展開してgit add .するのだが、今回は今まで使う機会のなかったgit submoduleを使おうと思った。man git submoduleしたところ使い方は簡単で、git submodule add URLするだけだ。

さっそくGitHubに上げてGitHub Pagesを有効にしたが、なぜか404、エラー内容を読むと、どうもGitHub Pagesのレポジトリでsubmoduleを使う場合は、URLはhttpsでなければならないそうだ。

Using submodules with Pages - User Documentation

まあ、たしかに理由はわかる。とはいえ、submodule先もgithubの場合、特別に対応することもできるのではないか。

submoduleのURLを後から書き換えるには、.gitsubmodulesを書き換えればよい。

https://github.com/EzoeRyou/slide-cpp17book

2018-03-11

プログラマの数学を読んだ

結城浩著、プログラマの数学を読んだ。

内容は高校数学程度のもので、2進数、論理、数学的帰納法、順列組み合わせ、再帰、背理法あたりは高校数学で出てきた記憶がある。

剰余と再帰はプログラマーならば誰でも知っているぐらいよく使うのだが、なぜか高校数学までの間に剰余と再帰を学んだ覚えはない。私の記憶では、除算を学び始めた頃は商と余りとを区別していたはずだが、その後、実数や分数がでて余りを意識しなくなってしまう。整数の商を求めるのが除算演算子なのだから、整数の余りを求める剰余演算子も小学校ぐらいで教えていい気がするのだが、なぜ日本の教育では剰余を教えないのだろう。数学的帰納法は再帰だと言われれば再帰ではある気がするが、再帰という概念は高校数学までにしっかりと出てきた記憶がない。パスカルの三角形は高校数学で出てきた気がするが、パスカルの三角形は組み合わせの再帰的定義で表現できるという話は出てきただろうか、記憶がない。

カウンタブルな集合というのは高校数学では出てこないが、整数列の集合や実数の集合がカウンタブルではないことの証明に、カントールの対角線論法が必要なのがよく分からなかった。というのも、別に対角線である必要はないように思われるからだ。例えば各実数の1番目とか2番めの数字を順番に並べた実数とかでもいいのではないか。なぜ対角線に取る必要があるのか。調べてみると、カントールの最初の証明は対角線論法を使っておらず、後に対角線論法を使った証明を思いつき、とても便利なので様々な証明に転用されているそうだ。

第二版では、機械学習の仕組みについて軽く触れている。

本の内容の半分ぐらいはすでに学んでいたことではあったが、改めて丁寧な説明を読むことで理解が深まる。

2018-03-09

江添亮の詳説C++17が発売された

C++17の新機能を余すところなく解説した参考書「江添亮の詳説C++17」が発売された。

江添亮の詳説C++17 (アスキードワンゴ)

3月9日から全国の書店の店頭に並んでいる他、アマゾンでは紙の本と不自由なKindle版を買うことができる。

達人出版からも電子書籍を買うことができる。

江添亮の詳説C++17【委託】 - 達人出版会

この本はGPLv3でライセンスされた自由な本なので、当然本のソースコードを公開している。

https://github.com/EzoeRyou/cpp17book

本はかなり早い段階からGitHubで公開して執筆していたが、461コミットあるうちの155コミットが筆者によるものなので、全コミットの2/3は他人のPRをマージしたものである。

出版記念の勉強会を3月14日に開催する。

歌舞伎座.tech 番外編「江添亮の詳説C++17」出版記念 - connpass

勉強会の会場でも本を買える手はずになっている。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2018-02-28

江添亮の詳説C++17出版記念勉強会を3月14日に開催

3月9日に発売される江添亮の詳説C++17の出版を記念して、3月14日に勉強会を行うことにした。

本の内容としては、2017年に発行された新しいC++17の新機能を余すところなく解説している。

本はGPLv3でライセンスされた自由な本であり、GitHubでソースコードが公開されている。

https://github.com/EzoeRyou/cpp17book

出版を記念した勉強会を3月14日に開催する。勉強会の詳細と参加登録は以下のconnpassのページにて確認できる。

https://connpass.com/event/80830/

当日は本を現地で販売できる見込みだが、数に限りがあるので確実に入手するためには、今から書店や通販Webサイトで予約注文をするとよいだろう。

最近、発表会と言うよりは、C++に興味がある人間が雑談をする場の方が有意義ではないかと思い、発表枠としてはLT枠のみを設けた。

本は購入するだけでは意味がなく、読まなければならない。今後、著者自ら読書会を開催しようと思っている。この本の所有者達が、広い部屋に、一斉に集まり、わざわざ読書会に参加したのだから、これはもう本を読むしかない。そのような状況をお膳立てするべきだろう。

さて、今年は入門書を書かなければならない。入門書の執筆は最も難しい。難しい機能を難しく解説するのは簡単だ。すべてを網羅的に記述すればいいだけだからだ。入門書は多くの詳細を大胆に省略、簡略化しなければならない。その結果、すべての入門書の内容は本質的に間違ったものになる。それでもなお間違いの少ない簡略化のルールを見いだせた入門書が良書となる。つらい仕事だ。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2018-02-24

NPM 5.7が重要なディレクトリの所有者を書き換える凄まじいバカをやらかす

https://github.com/npm/npm/issues/19883

Do not use NPM 5.7 | Hacker News

NPM 5.7において、sudo npmを非rootユーザーから行うと、/etc/とか/usrとか/bootなどの極めて重要なディレクトリの所有者を、sudo npmを実行した非rootユーザーにchownして書き換えてしまうというとてつもないすさまじい不具合が報告されている。

一体どうすればそんな間違いをしでかすというのか。

https://github.com/npm/npm/commit/94227e15eeced836b3d7b3d2b5e5cc41d4959cff

どうもディレクトリを作成するときにパーミッションと所有者を適切に設定するという名目でmkdirをラップして実行時のユーザーでchownするcorrectMKdirを作ってmkdirを置き換えたようなのだが、そもそもsudoしたユーザーがroot権限を持つユーザーである保証はなく、そもそも/etcや/usrの所有者であるユーザーである保証もなく、本当にNPM開発者は本来とっくの昔に解決したはずの問題を、ぼくちんのかんがえたさいきょうのほうほうで引っ掻き回すことにかけては驚異的な才能を発揮するのに余念がない。これだから特定の言語専用のパッケージマネージャーというのは使うべきではないのだ。

2018-02-21

C++をプログラミング入門に使うならHTTPSぐらい喋れないと話にならんと言われたのでそういうライブラリを作った

C++17の新機能を余すところなく解説した「江添亮の詳説C++17」は3月9日に発売される。今はC++によるプログラミングの入門書を書こうとしているが、同僚から、果たしてC++をプログラミング入門に用いるのは適切なのだろうかという疑問を提示された。私はC++はハードウェアに直接マッピング可能な低級機能からそれを隠匿する高級機能まで揃っている上に、継ぎ接ぎだらけの型システムは

「21世紀の入門コード片という意味では https download くらい標準で喋って欲しさ」

と言われた。なるほど、そういうのはsystem("wget -q https://example.com")すればいいのではないだろうか。

「なるほど、しかしそれではファイル経由で扱うことになる。初心者ならstd::stringとかに入った状態で扱いたいはずだ」

一理ある。そういうライブラリを実装すればいいのではないか。せっかくだからpopenを使って標準出力をパイプで受け取り、それをistreamにしてみよう。幸い、libstdc++にはstdio_filebufがあるのでFILE *からfilebufが作れる。

というわけで以下のようなライブラリを作った。

int main()
{
    popen_istream ps("curl -s https://example.com") ;

    std::string line ;

    while (ps)
    {
        std::getline( ps, line ) ;
        std::cout << line << '\n' ;
    }
}

とりあえず動く。

「しかし、HTTPSをお話したい理由というのは、サーバーの提供するWeb APIを叩きたいためだ。そのためにはサーバーにPOSTでデータを送りつけられるとなおよい」

wgetは標準入力からPOSTで送りつけるデータの入力に対応していないが、curlは対応している。なのでパイプで標準入力にデータを流し込み、標準出力をパイプで繋げばよいのではないか。

popenは入出力双方向のパイプに対応していない。この理由は、デッドロックを起こしやすいためだ。結局、入出力のバッファリングがユーザースペースで行われている場合、実際にパイプに書き込まれるタイミングが想定と異なる場合があり、また多くの伝統的なコマンドも、標準入力をすべて読み込まないうちは出力を始めないような設計のものも多いためだ。

なので、入出力を双方向にパイプするには古典的なpipeを使ってやる必要がある。iostreamはistreamとostreamで別々のfilebufを持てるためこのような入力先と出力先が違う場合にも対応できる。istreamとostreamが別々なので、ostreamにすべて書き込んだ時点でパイプを破棄することもできる。

とここまで考えて思ったが、やはり標準に高級なネットワークライブラリがほしい。HTTPSをお話できたりブラウザー操作ができたりするようなライブラリだ。

class popen_filebuf
{
    FILE * fp ;
    __gnu_cxx::stdio_filebuf<char> fb ;

    static FILE * init_popen( std::string_view command,  )
    {
        std::string cmd( command ) ; // for null-terminated c_str()
        FILE * result = popen( cmd.c_str(), "r" ) ;
        if ( result == nullptr )
            throw std::runtime_error("popen failed.") ;

        return result ;
    }

protected :
    auto get_filebuf_ptr() noexcept
    {
        return &fb ;
    }
public :
    popen_filebuf( std::string_view command )
        :   fp( init_popen( command ) ),
            fb( fp, std::ios_base::in )
    { }

    ~popen_filebuf()
    {
        std::fclose( fp ) ;
    }

} ;

class popen_istream :
    protected popen_filebuf,
    public std::istream
{
public :
    popen_istream( std::string_view command )
        :   popen_filebuf( command ),
            std::istream( get_filebuf_ptr() )
    { }

} ;



std::string popen_reader( std::string_view command )
{
    popen_istream ps( command ) ;
    
    std::istreambuf_iterator<char> iter( ps.rdbuf() ), end ;
    std::string buf( iter, end ) ;
    return buf ;
}

2018-02-11

アマゾンで江添亮の詳説C++17が予約可能になった

江添亮の詳説C++17 | 江添 亮 |本 | 通販 | Amazon

2017年に発行された最新のC++17の新機能をあますところなく解説した私の本、江添亮の詳説C++17がアマゾンで予約可能になったようだ。

本の内容はすでにGitHubで公開している。ライセンスはGPLv3だ。プログラミングの参考書は自由なライセンスで提供されるべきである。

https://github.com/EzoeRyou/cpp17book

次は入門書とTips集を書きたい。

2018-02-09

新しいプログラミング言語を学ぶということ

去年の暮から一ヶ月ほど、Haskellを学んでいる。目的は色々あるが、まったく新しいプログラミング言語を学ぶ経験をもう一度するのが最大の目的だ。

C++17の新機能を余すところなく解説した「江添亮の詳説C++17」は3月に出版される。C++20にはまだ間がある。C++の入門書を書く絶好の機会だ。入門書というのは毎月腐るほど出版されているが、良書は少ない。結局、参考書の中で最も売れ行きが容易に予想可能なのは、最も読み手がいるであろう入門者向けの本であり、入門書の出版がいたずらに増え、粗製濫造されているとみえる。入門書は上級者は読まないので適切な批判もされにくいのでこのような惨状になっているのだろう。

私の入門書はそのような悪書にしたくない。しかし、私はすでにC++の初心者ではないし、C++の初心者がつまづく点がわからない。というより、ここしばらくまったく新しいプログラミング言語を学んだことはない。C++以外にもPython、JavaScript、bashなどを必要に迫られて書き散らすこともあるが、相当古いJavaScript以外は真剣に学んだことがない。

これはよくない。入門書を書く前に、少し時間を割いてでも、全く新しいプログラミング言語に入門すべきだ。そのための言語としてはHaskellがふさわしい。と、こう考えた。

なぜHaskellなのか。HaskellはC++とは全く違った言語だからだ。例えばJavaScriptは表面的にはC++とかなり似た文法を持っているので、全く新しいプログラミング言語を学ぶ目的には使えない。PythonやRubyは文法的には少し違うが、すでに触ったことがあり、それほど苦労した覚えがないのでやはりだめだ。Scalaは汚らわしいJavaの実行環境を私の神聖なメインPCにインストールしたくないために不適だ。

Haskellを学ぶには、Learn you a Haskell for great goodという本が良いらしいので、早速買い求めて読み始めた。この本はとても軽くて読みやすい本だ。そしてユーモアが多い。真面目な参考書に個々までのユーモアは必要なのかと疑問に思うぐらいに多いのだが、しかし全くの初心者が読む本には、これぐらいのユーモアが必要なのではないかと思う。

というのも、だ。私自身、久しぶりに経験して驚いているのだが、全く新しいことを学ぶのは途方もなく疲れる上に非効率的な作業だからだ。不思議なもので、それほど難しいはずはない内容なのに、なぜかなかなか頭に入らない。一日に本を読む時間は何時間もあるが、短期的にいくら時間をかけても内容が頭に入ってこない。一晩寝るなどして時間を開けないとわずか数ページの内容も読み進めることができない。文字を読むことはできるにしても、その内容が理解できず、また残らないとしたら意味がない。

そういう賽の河原のような不毛な作業を続けるには、ユーモアがとても効果的だということがわかる。ただでさえ退屈な作業なのに、ユーモア欠落症患者によって書かれた文章まで読まされるのでは続くものも続かない。

私が書く入門書にはユーモアが必要だということがわかる。

プログラミング言語を学ぶには、プログラミングの実行環境が手元にあったほうがよい。しかしHaskellの実行環境はあまりすぐれているとは言い難い。Haskell PlatformはDebian系ならばapt一発で入るのでまだいいのだが、クールなキッズは皆使うというStackは、私の手元ではまともに動いた試しがない。

そもそもだ。CabalもStackもてんでなっていない。パッケージマネージャと名乗るのもおこがましい。だいたい管理できていない。パッケージを追加することはできるが削除できないのだから。削除するにはどうするか? すべてのパッケージを削除して最初からインストールをやり直す。富豪にもほどがある。Stackもだめだ。結局管理できていない。管理できないからどうするか? とりあえずプロジェクトごとに特定のディレクトリ下に全部環境を構築しよう。富豪にもほどがある。

そういうわけで、Haskellの実行環境を整えるだけで1日を浪費した。C++の入門書では環境構築についてそれなりにページを割かなければならないと痛感した。具体的にはWindowsとMacはC++の学習に不適切なOSなのでGNU/Linuxを推奨したい。主要なディストロならC++の実行環境はデフォルトで入っている。

さて、そうこうしているうちに一ヶ月たち、流石にHaskellである程度のコードは書けるようになってきた。まだモナドについて完全に理解していないのだが、理解できるのも時間の問題だ。なんだ、Haskellも言うほど難しくはないではないか。

しかし、プログラミング言語の学習に当たってはこの時期が一番つらい。プログラミング言語の学習過程では、序盤はさっぱりわからず、中盤はすべてを理解したつもりになり、終盤でやはりわからない状況になる。

プログラミング言語の学習の中盤でつまづくのは、言語の以外な落とし穴だ。例えば私の場合は以下のような例で躓いた。

モナドを学び始めたので、確認がてら、以下のようなコードを書いた。

getContents >>= 複雑な式>>= putStr

しかしこれでは見づらいので、複雑な式を関数に分けることにした。複雑な式の中身は特に重要ではないので、ここでは単にpureとする。

-- こうすればカリー化によって引数を書く必要がないぞ。Haskellは完全に理解した。
f = pure
getContents >>= f >>= putStr

その後、fはそのままにしたまま別の処理を試したくなった。

f = pure
getContents >>= 別の式 >>= putStr

するとエラーになった。意味がわからない。

Haskellではf = pureと書くとfは多相にならず、型を決定しなければならないが、型を推論するための文脈がないのでエラーになるというのが原因だ。解決方法としては、fの型を明示的に書く、引数を書く、GHC拡張を使うなどの方法がある。

しかし、これは割と初心者が引っかかりやすい落とし穴ではないか。例えば以下のコードがなぜエラーになるか、初心者がわかるのだろうか。

f = pure
main = do
    print ( f 0 == Just 0 )
    print ( f 0 == [0] )

どうでもいいことだが、C++を長年やっていた人間として、f = pureとしたあとにf 0 == [0]と書くと、fはpureになり文脈上リストなのでf 0は[0]になるというのは割と驚きがあるし、リストという割と特別扱いされているような昨日でさえ、単なるライブラリ実装であり、(:)はデータコンストラクターにすぎないというのも驚きがある。

早くモナドを完全に理解したい。

2018-02-05

Haskellで書いてみたらC++の10倍遅かった

エレガントな解法、エレファントな解法 〜モンテカルロ法を添えて〜

コインを100回投げたうちに、表もしくは裏が連続して10回でる確率をモンテカルロ法で計算する。

なにはともかくC++で実装してみた。

template < typename Random >
bool coin_toss( const unsigned int try_count, const unsigned int length, Random & r )
{
    unsigned int count{} ;
    int prev{} ;

    std::uniform_int_distribution<> d( 0, 1 ) ;

    for ( unsigned int i = 0 ; i != try_count ; ++i )
    {
        int result = d(r) ;
        if ( result == prev )
        {
            ++count ;
            if ( count == length )
                return true ;
        }
        else
        {
            prev = result ;
            count = 1 ;
        }
    }

    return false ;
}

template < typename Random >
double monte_carlo( unsigned int try_count, Random & r )
{
    unsigned int count{} ;
    for ( unsigned int i = 0 ; i != try_count ; ++i )
    {
        if ( coin_toss( 100, 10, r ) )
            ++count ;
    }

    return double(count) / double(try_count) ;
}

int main()
{
    std::array<unsigned int, sizeof(std::mt19937)/sizeof(unsigned int)> c ; ;
    std::generate( std::begin(c), std::end(c), std::random_device{} ) ;
    std::seed_seq s( std::begin(c), std::end(c) ) ;
    std::mt19937 engine(s) ;

    for ( unsigned int i = 100 ; i != 1000000 ; i *= 10 )
    {
        auto r = engine ;
        std::cout << i << "\t : " << monte_carlo( i, r ) * 100.0 << "%\n" ;
    } 
}

C++11から高度な乱数ライブラリが使えるようになったのだが、現在、実行時に適切に初期化する方法に面倒なボイラープレートコードが必要だ。実行時に乱数で初期化してくれる機能が現在提案されている。

ところで、最近Haskellを学んでいるので、このコードをHaskellでも書いてみようと思った。

まずは乱数だ。コインの表裏はBoolで表現するとして、Haskellらしく無限の乱数リストを生成しよう。

coin_seq :: (RandomGen g) => g -> [Bool]
coin_seq gen = randoms gen

あとはこれをtake 100して一回分の試行とする。1000回試行したければ、drop 100したのを再帰的にtake 100すればよい。しかし、もっといい方法がある。要素数100の[Bool]が入ったリスト、つまり[[Bool]]を無限に作ればいい。そのリストをtake 1000すれば1000回の試行分になる。

split_n :: Int -> [a] -> [[a]]
split_n n seq = take n seq : split_n n (drop n seq)

さて、seq_n = take 100 $ split_n 100 (coin_seq gen)のようなリストseq_n :: [[Bool]]は作れた。あとは[Bool]に連続した要素がn個あるかどうかを調べるcoin_toss nと、それをリストのすべての要素に対して行うmonte_carloを書けばいいだけだ。

coin_tossが結果をBoolで返すとすると、とりあえずseq_nにcoin_tossをmapしてTrueだけfilterして、その結果のリストの要素数を数えれば、成功した試行数がわかる。あとは試行数で割って確率を求めればいいだけだ。

monte_carlo :: Int -> [Bool] -> Double
monte_carlo try_count seq = ((fromIntegral n) / (fromIntegral try_count)) * 100.0
    where
        seq_n = take try_count (split_n 100 seq)
        n = length . filter id $ map (coin_toss 10) seq_n

coin_toss len seqはInt -> [Bool] -> Boolな関数で、seqの中にlen個の連続したTrueもしくはFalseがあるかどうかを数えればよい。

いろいろ考えたが、まずgroup seqして連続した同じ要素を分割して[[Bool]]を作り、それぞれの[Bool]の要素数をいれたリスト[Int]をmapし、len以上の要素だけをfilterして、結果のリストに要素があればTrueを返す計算をすればいいのではないか。つまり、

has_contiguous_elems :: (Eq a) => Int -> [a] -> Bool 
has_contiguous_elems len seq = not $ null $ filter (>= len) $ map length (group seq)

coin_toss :: Int -> [Bool] -> Bool
coint_toss _ [] = 0
coin_toss len seq = has_contiguous_elems len seq

となる。全体的にはこうだ。

import System.Random
import Data.List

coin_seq :: (RandomGen g) => g -> [Bool]
coin_seq gen = randoms gen

split_n :: Int -> [a] -> [[a]]
split_n n seq = take n seq : split_n n (drop n seq)

has_contiguous_elems :: (Eq a) => Int -> [a] -> Bool 
has_contiguous_elems len seq = not $ null $ filter (>= len) $ map length (group seq)

coin_toss :: Int -> [Bool] -> Bool
coint_toss _ [] = 0
coin_toss len seq = has_contiguous_elems len seq

monte_carlo :: Int -> [Bool] -> Double
monte_carlo try_count seq = ((fromIntegral n) / (fromIntegral try_count)) * 100.0
    where
        seq_n = take try_count (split_n 100 seq)
        n = length . filter id $ map (coin_toss 10) seq_n

main = do
    gen <- getStdGen
    let s = coin_seq gen
        in mapM (\n -> putStrLn ((show n) ++ "\t : " ++ (show (monte_carlo n s)) ++ "%") )
                [100, 1000, 10000, 100000] 

このコードは動いた。ただし、最適化オプションを使っても、C++の10倍遅かった。

やはりlen個の連続した要素が存在するかどうかを調べるhas_contiguous_elemsが遅いのではないかと思い、これを再帰で実装することにした。

has_contiguous_elems' :: (Eq a) => Int -> [a] -> Bool 
has_contiguous_elems' _ [] = False
has_contiguous_elems' len (x:xs) =
    if count >= len
        then True
        else has_contiguous_elems' len $ dropWhile (== x) xs
    where count =  1 + (length $ takeWhile (== x) xs)

この実装に差し替えたところ、実行速度はC++の9倍遅かった。

すると、他の部分もリストからリストを生成するという記述をやめて、再帰で実装すればもう少し早くなるのだろうか。

そして思うのは、同様のリストからリストを清々するような処理は、所詮リストのメモリーサイズがキャッシュに収まる程度なので、C++で書くとHaskellより早いのではないかとも思ったが、まだ試していない。

2018-02-04

年収1200万円と2億の資産でできる贅沢はパトロネージュ

以下のはてな匿名ダイアリーの記事が注目を集めている。

贅沢な生活って何が楽しいの?(追記しました

独身34歳男、年収900万+配当収入300万くらい。

贅沢の良さがわからない。

家は相続で貰ったので家賃無し。金融資産は相続したものと合わせて2億を超えた。

生活費は月に12万くらい。配当込みで年間800万以上金が増えていく。

別に金を使うのが嫌いなわけではない。ただ、使う気がおきない。

この増田は1200万円の年収と2億の資産を保有している。増田が過去に行った贅沢は以下の通り。

  • 飛行機のファーストクラス(100万円)
  • ホテルのスイートルーム(100万円)
  • オーダーメイドのスーツ(50万円)
  • 懐石料理(20万円)
  • ステーキ(10万円)

これらの贅沢がありきたりでつまらないのは当然だ。なぜならば、これらの贅沢には、何も1200万円の年収と2億円の資産は必要ないからだ。ただ100万円を貯金して一度に使えばできる程度の贅沢だ。100万円を1年ぐらいかけて貯金するのであれば、34歳男の平均年収である400万円でも可能だ。

せっかく贅沢をするのであれば、年収1200万円と2億円の資産をもって初めて可能になる贅沢をするべきだ。では増田の境遇ではじめて可能になる贅沢とは何か。多額の借金と長期的な支出だ。そして、究極的にはぱとろネージュと呼ばれる行為、すなわち食客を抱えることだ。

多額の借金

増田のような境遇にない我々凡人は、それほど多額の借金ができない。大抵の凡人が生涯に負うことのできる多額の借金は、奨学金と住宅ローンぐらいなものだろう。しかも学費や住宅といった目的が限定されている。

しかし増田は違う。1200万円の年収と2億円の資産を担保に、1億や2億の借金ができるだろう。借金ができる環境はとても贅沢だ。借金で得た金を使って利息を上回る利益を出すことができれば借金をした以上の価値を生む。例えば増田は自分の興味がある事業を立ち上げることができる。ただし、これには利息を上回る利益を出すことができずに資産を失うリスクはある。

長期的な支出

増田が例に挙げている贅沢は、短期的な一度きりの支出ですむものだ。100万円を払ってファーストクラスに乗ったりスイートルームに泊まったりするのはいかにも贅沢に思えるが、一回払うだけでその後は何の支出もいらない。

しかし増田は違う。増田は月に50万円ぐらいの支出を長期的に続けることができる。長期的に支出を行えるのは、我々凡人には不可能な贅沢だ。では、長期的な支出が必要な贅沢とは何か。

答えは人だ。増田は長期的に人をフルタイムで雇うことができる。増田は秘書を雇い日常の雑事をすべて押し付けることもできる。増田の時間は貴重である。増田がファーストクラスやスイートルームや懐石料理を楽しむとして、その予約作業という雑事は、わざわざ贅沢な増田の手をわずらわす作業ではない。秘書にやらせればよい。

そして、古来より最高の贅沢とされる人への支出がある。パトロネージュ、すなわち食客を抱えることだ。

増田にはより発展してほしい芸術や学問はないだろうか。もっと具体的に書こう。自分の気にいる漫画や小説を読みたい。自分の気にいるゲームで遊びたい。ある自由なソフトウェアに自分の望みの機能を追加したい。ある病気を根絶する研究が進んでほしい。ある技術がもっと発展してほしい。しかし、増田は芸術や学問を極めることはできない。増田に絵や詩人の才能はなく、プログラミングはできず、医学博士や工学博士として研究に身を捧げる人生も送りたくはないとする。しかし、世の中には芸術や学問に身を捧げたいと願う天才はいる。増田はそのような天才を食客として衣食住の不便をなくし、芸術や学問を追求させることができる。

増田が増田を書くことができるのは、コンピューターが発展したからだ。ところで現代のコンピューターの発展はチャールズ・バベッジの研究に負うところが大きい。もしチャールズ・バベッジがコンピューターの研究に打ち込まなければ、コンピューターの発展は数十年は遅れていただろう。チャールズ・バベッジは裕福な家の出身ではあったが、コンピューターの研究のためにパトロンが必要だった。

この話の教訓としては、自分が楽しむためにカネを使えないのであれば、他人が楽しむためにカネを使ってみてはどうか。その結果として芸術や学問が発展するのであればこれ幸い。

2018-02-02

江添ボドゲ会@2月11日

だいたい毎月行っている自宅ボドゲ会を2月11日に開催します。

江添ボドゲ会@2月11日 - connpass

2018-01-28

CoinCheckとNemの騒動から暗号通貨について思うこと

何から語ろうか。まずCoinCheckにしよう。CoinCheckという暗号通貨の取引所が、NEMを大量に盗まれたという事件だ。私の法と技術の理解では、盗むというのは物理的な物が伴うので映画泥棒という言葉が法的に正しくないのと同様に違うのではないかと思うんだが、まあそこは置いておこう。ここでは単に悪意としておく。

これについて、自分のNEMが悪意されたのでCoinCheckに金を返せと叫んでいる人間のほとんどは、そもそも筋が悪い。もし、Bitcoinが花開いた暗号通貨が技術的に正しく運用されていたならば、そんなことは起こりようがなかったのだ。つまり、しっかり自分の手元の信頼できる環境でフルノードを実行し、物理的なコンピューターの前には武装した警備員を配備するべきだったのだ。自分でフルノードの実行もせずに、秘密鍵すらCoinCheckに知らせ、やれ盗まれたのなくなったのというのは、紙に印刷してある資料を電子媒体で送れといったら、紙をスキャンした画像をPDFやEXCELに貼り付けて送ってくるバカにも等しい愚かな行為だ。非科学的なアメリカ人は神によって通貨の価値を信じているが、我々科学の信奉者は計算力に裏打ちされた通貨を信じる。計算力の強いやつは正しい。それが暗号通貨の基本的な理念ではなかったのか。

世間では秘密分散共有によるマルチシグネチャーがどうのとか、ホットウォレットがどうのと言っているが、正直本質ではない。秘密鍵を分散させようと、エアギャップさせようと、守りが弱ければ、銃で武装した数人によって脅迫、拷問された末に情報を吐き出すのがオチだ。

さて、今回の事件の記者会見において、NEMのロールバックという面白い概念が提唱された。ロールバック、取引をなかったことにするという救済措置、これについて考えてみよう。

そもそもBitcoinから始まった、あまり正確ではないが俗にブロックチェーンと呼ばれる暗号通貨は、取引の上に取引を重ねる仕組みになっている。

例えば、アリス, ボブ, チャーリーによる取引が、アリス→ボブ→チャーリーの順番で行われた場合、取引チャーリーの取引はボブの取引が成立した上に成り立っており、ボブの取引はアリスの取引が成立した上に成り立っている。

すると、アリスの取引をロールバックするには、ボブとチャーリーの取引もロールバックしなければならないことになる。

もう少し読者が実感できる例で考えてみよう。今週、読者は給料日だったのでまとまったカネを持っている。いまからオーガニック・スシを食べようと出かけたところだ。スシ・レストランに向かう途中の自販機で、財布の中に残っていた小銭で代用ジュースを一本買った。そこに急に、日本自治区政府からのエージェントがやってきて、君に告げる。「君、実は先週、JPYの大量盗難が発生した。ついては被害者救済のために、先週に遡ってJPYの取引をすべてロールバックしたい。全員の同意が必要だ。君が今買った代用ジュースの代金は戻ってくるが、君の給与振込はなかったことになる。被害者救済のため、模範的な一般市民である君はロールバックに同意してくれるだろうね? いや、カネはなくなるわけじゃない。一週間前の状態に戻るだけなんだ。あとで必要な取引は各人で復旧してもらいたい」

読者は同意するだろうか。

しかし、全員が同意するのであれば、アリスの取引だけをなかったことにして、ボブとチャーリーの取引は存在したことにできないだろうか。もちろんできる。それはハードフォーク(通貨の分裂)と呼ばれている。

しかし、我々は計算力によって通貨を信用していたのだ。アリスの取引を無効にすると、その取引に連なるボブとチャーリーの取引は計算では信用できなくなる。しかし、皆がアリスの取引を無効にすることに同意するならば、計算力を持つ皆が信用しているので正しい。自分だけアリスの取引は発生したと主張することは可能だが、過半数がその主張を拒否するのであれば、もはやその価値はなくなる。すると、世の中にはアリスの取引が存在した通貨と、存在しなかった通貨が生まれることになる。どちらを信じるのも自由だ。両方信じてもよい。こうして通貨は分裂する。

わかりやすい例で考えてみよう。日本自治区政府のエージェントは君にこう告げる。「いまから先週発生したJPYの大量盗難の取引を取り消す作業をする。君の財布の中身、銀行口座の金額、その他あらゆるカネとその記録を出し給え。我々がJPYの盗難だけがなかったように書き換えて君に返す。今のカネの状態はすべて破棄される。我々の書き換えは信頼できる。模範的市民の同志、同意してくれたまえ」

読者は同意するだろうか。

今回、このどちらの方法もNEM財団は取らなかった。仮に取ったとしても、マイナー達の同意を取り付けることはできないだろう。

かわりにNEM財団がやったのは、悪意を持った転送先のアドレスに、盗難を意味するモザイクを付与することだ。これはNEMの機能で、詳しくは調べていないが、ここで重要なのことは、アドレスにタグ付けができるということだ。NEM財団が今回悪意を持って取引されたNEMを含むアドレスにすべて盗難タグ付けをしていくことで、そのアドレスとの取引を利用者に拒否するよう促す。これにより、悪意ある者の持っているNEMは私情でかちを失うという目論見だ。なるほど、窃盗アドレスだと知った時点ですでに善意の第三者ではなくなるから、法的にも効果的だ。

しかし、果たしてそううまくいくだろうか。今回の犯人が次にやるべきことは、NEMを小額づつ、適当なアドレスに片っ端から送りつけることだ。大多数のアドレスが窃盗タグで汚染されてしまうと、もはや窃盗タグは意味を為さなくなる。第一、そのタグ付けは計算力に裏打ちされているのだろうか。権威がつけたタグを盲信しているだけではないのだろうか。そして、権威は果たして信用できるのだろうか。するとNEM自体の価値も、果たして信用できるのだろうか。

ただし、この考え方は面白い。我々は権威と計算力のハイブリッドの信用通貨を作り出してもいいのではないだろうか。

通貨の歴史を考える。貴金属のようなもともと価値のあるものが取引されていたのが、貴金属を直接取引するのは非効率的なので、貴金属と交換できる引換券で取引するようになった。しかし、実際に存在する貴金属以上の借金が市場に出回り、この仕組みは崩壊した。今の国家に裏打ちされた通貨は、貴金属と直接交換を保証されていない。

世の中には、存在自体が価値を持つ権威が存在する。国家もそうだが、宗教開祖とかアイドルとか秒速で億ぐらい稼ぐ人とかだ。そういう信者を何十万、何百万と持つ権威が、Bitcoinのような既存の暗号通貨をhard forkして独自の暗号通貨を始めるのはどうだろうか。何十万、何百万の妄信的な信者が価値を認めるのであれば、その暗号通貨には実際に価値が出るだろう。するとマイナーも一枚岩ではなくなるので、誰も過半数の計算力を持つことができずに、マイナーは単なるトランザクション処理係に成り下がる。何か問題が起きれば、権威がイスラム教で言うところのファトワー(見解)を出して訂正するのだ。

と考えてみると、VALUは案外いい線をいっていたのではないかとも思えてしまう。もちろん私は信用しないが。

こうして考えてみると、計算力と権威のハイブリット信用通貨は、国家から通貨発行権を奪還する試みであるとも言える。面白い世の中になってきたが、私としてはもっと現実的な価値を提供してほしい。例えばチューリング完全な計算を提供するとか、実際ストレージとして使えるとか、契約への同意が行われたことの記録ができるとかのブロックチェーンネットワークがほしい。