/ 最近 .rdf 追記 設定 本棚

脳log[2019-11-05~]



2019年11月05日 (火) ミネルヴァの続刊をずっと待っていたのだけど、そのせいで他のシリーズに手を出せないでいたのだけど(そういう気質、あるよね)、作家には続刊か新シリーズかのオプションが与えられており、選んだ結果の新シリーズだったらしい。20190703のスライドの作者のツイッターからあいだに一人を挟んで再び名前を見かけることがなければそれまでだった。それは惜しい(どっちが?)。


2019年11月04日 (月) ひこにゃん(?)のアイコンでツイッターをやっている人をブックマークしていて、なんとなし歴史・地理・漢字クラスタに分類していたのだけど、ふいに AGC(AtCoder Grand Contest)に参加した話が出てきたりもして、たった一人の人間であっても底は知れない。


2019年10月31日 (木) 疑問に対する答え。「関心の分離や単一責任の原則に通じるところがあるんでしょうか?」■もっとミクロな話で、曖昧さを残さない、惑わせない、その余地を残さないってことだと理解している。■今回の件で言えば、ヌル終端されないケースがあるのかないのかということ。実際は固定長配列で間に合うのだから用意された配列にヌル文字が含まれないケースは存在しないと考えられる。だから仕様でヌル文字の存在を仮定する。存在しない場合を許さないし仮定しない。それが Assertive であるということ。■曖昧な態度をとれば論理がつながらないし、すべてのあり得るケースを十全にカバーしようとしたときに負担が増える。想定ケースに対して念のために1だけ余分に対応できるようにしたコードに対応するためにさらに1の余分が必要になり、それに対応するコードはさらに……。■カバーする必要性に気がつかずに、論理のギャップに対して2人の人間が異なる見方をすれば、それがバグの始まり。■追加された比較演算子のテストはヌル文字が存在しないケースにアイデンティティを与えて存在を認め、仕様として規定した。だとすれば今後(そして既存のコードも) MYDEVMODE の sz と名の付くメンバにヌル文字の存在を仮定することができなくなり、たとえばメッセージボックスをはじめとする文字列関数にそのまま渡すことがバグの温床になる。律儀にやるなら _MAX_PATH+1+1 のバッファに一時コピーしなければいけない。正気か?■現実をテストケースにすれば実装をいじる必要はなかった。実在しないケースをテストにして実装をそれに合わせたのがあの PR。正気か?■俺は怠け者だから行動する者には負けるけど(「うんこコード、放置しててすまんです」)、その動きが右へ進み左へ進みその間に後退もしている(前進はしていない)、というものではないかという疑いの目は向けている。■■■「一応、strncpy的な関数の使い方を誤るとNUL終端されない文字列を作れますので、絶対要らない対応、というわけでもないと思ってました。」 テストに対する勘違いがあると思う。ヌル終端しないコードに対してこのテストと実装の修正で何ができるのか、シナリオで示して欲しい。もちろんそれを伝えはしない。聞く耳ねーからな。無駄無駄無駄。■念のために書くけど、「ヌル文字の存在を仮定する」というのを「ヌル文字の存在を信じて暴走すべき(それを許容すべき)である」などと曲解されていては全く浮かばれない。ヌル文字の後ろを比較対象にするのがあるべき仕様の外であるなら(wmemcmp を使わない理由)、構造体のために確保されたメモリの外を比較対象にするのもあるべき仕様からは外れている(wcsncmp を使う理由)。どちらも否定していないし、今は無関係。混同している人間が誤っている。


2019年10月30日 (水) ぶん殴りたい。共通の理解の上で意見が合わないのなら、それは価値観の違いであり、それをどうこうすることはできない。だけどある程度共通のものがないとどうしたって戦争が避けられないから、批判に堪える出版物を引用する。自分個人の考えや感覚でそれができるとは考えない。しかし価値観以前に共通の理解をこの者との間に築くことができないせいで、無駄に消耗する。全くの無益。耳を塞いで他人にでたらめな要求を押し付けるふるまいを「犯罪的」だというのだ。自己の無謬性にそこまで確信を持てるとは大した自信家じゃないか。「本物は違う」とはこのことではないか。俺の方はといえば事実関係に白黒が付かないことに気も狂わんばかりになっているというのに。■https://github.com/sakura-editor/sakura/pull/1081#pullrequestreview-307582232 の指摘は最初から十分に理解できるものだった(なのに不備を詫びることができるのは報告者の人徳だ)。ここにアクセス違反のおそれがあるとヒントを与えられても見つけられない者に、最初から何が期待できるのかという考えもある。万事この程度の理解度で弁明する者のいない既存コードをふんわりざっくりけなすようなまねをするから、「お前が」「(わざわざ)言うな」の念が募る。■俺はこの者の人格に絶望している。


2019年10月29日 (火) 日曜日にあった ABC。ちょっと毛色が違った D 問題。「D - Water Bottle」■難しポイント。sin と tan 間違えた。弧度法から度数法への変換を間違えた。高校数学では tan/sin/cos しか習わないので Ruby の Math モジュールのドキュメントを漁って atan と atan2 と atanh のどれが自分の求めるものか確かめないといけなかった(しかも最初 sin 系の関数を試していて角度の変換も間違えた)。これが難しいとか高校生に鼻で笑われる。


2019年10月26日 (土) もうはばかる理由もないので最初(sourceforge.net)から思っていたことを書くけど、「定石だから」ってのは理由になりはしない。そもそもその「定石」がローカルルールや迷信の類ではないのかという疑いがあるが、そこをクリアしたとしてもやはり同じ。デザインパターンがそうだ。広く流布し認められたパターンであっても、パターンカタログに載っていること自体が、パターンを採用する理由になるわけではない。これまで読んだどのパターン本でも、パターンが適用できる具体的なシナリオと、パターンが持つメリットとデメリットの両方と、同時に比較考量すべき別のパターンが併記されていた。「定石だから」で留まるのは浅はかなんだ(「手段を目的化してしまうと見失いがち。手段は常に目的に対してテストされ、いつでも置き換えられなければいけない」)。盲信するならせめて対象として権威を選ぶくらいはしないと馬鹿なんだ。


2019年10月25日 (金) Android 9 Pie にインストールした VLC for Android 3.1.4。ファイルからの相対パスで音楽ファイルを列挙した m3u プレイリスト(文字コードは UTF-8)。パスに [] を含んでるファイルを再生してくれないので、それぞれ %5B%5D に置換する必要があった(※手を加えたのはファイルシステム上のパスではなく、プレイリスト内のパス)。なんで? 二重にパーセントエンコードされても不思議じゃないんだけど、なんで OK なの? これじゃ %5B という3文字を含むパスと [ という1文字を含むパスを区別できないじゃない。


2019年10月21日 (月) 旅行予約サイトの「今あなた以外に○○人が見ています」はウソだったことが判明 - GIGAZINE」■まじめに実装すると人とサーバーにコストがかかるし、下手すると逆効果(「今あなた以外にゼロ人が見ています」)の可能性があるので、完璧にコスト(手段)とパフォーマンス(効果)を最適化した結果だと思う。手段を目的化してしまうと見失いがち。手段は常に目的に対してテストされ、いつでも置き換えられなければいけない。


2019年10月17日 (木) 提出 #8002336 - AtCoder Beginner Contest 088」に対して1バイト縮めた「提出 #8002578 - AtCoder Beginner Contest 088」。でも Ruby で *最速* である hanada3355 という人の「提出 #5777010 - AtCoder Beginner Contest 088」を手直しするだけで 151 バイトのスクリプトになるんだよなあ(※p の引数解釈とか条件演算子と文字リテラルの解釈揺れをバージョン2.3.3に最適化すると多少縮むかも)。196 バイト、195 バイトのレベルではない。手法としては「ちょっとだけGOLFに走った」と同じなんだけど、見てしまってから真似はできない。発想の転換が欲しい。■とか書いている間に 187 バイトの「提出 #8002816 - AtCoder Beginner Contest 088」と 186 バイトの「提出 #8002824 - AtCoder Beginner Contest 088」。目の付け所がずれている。でも自分としては添削を受けているようでテクニックの引き出しが増えて良い。■■■矢継ぎ早にくり出される新アイディアが楽しい。特に出力変数 c に例外値 -1 の役割まで持たせてループのストッパーにするこれが白眉。「提出 #8007594 - AtCoder Beginner Contest 088」。■これもえげつない。「提出 #8007675 - AtCoder Beginner Contest 088」 Integer#to_i(2) のリテラル2を再利用するために t の初期値を1から2にしてしまう。つじつまを合わせるために問題由来のビット列 s の方を2倍してしまう。それでは釣り合わないんだけど W の代入文が省けるのと、2倍した s がループの停止条件としてそのまま使えるので総合して得する。■短いソースに何重にも意味を重ねてすべてがすべてと必然的に絡み合う感じ。最適化の極みよな。アルゴリズムと言語と個々の問題に対する深い理解がないとここまで自由にいじくれませんよ。


2019年10月15日 (火) 宇宙ツイッタラーXさんのツイート: "AtCoder Problems を更新しました。難易度推定アルゴリズムが改善され、いくつかの問題で難易度が低めに出ていたものが修正されました。 by @pepsin_amylase"」■AtCoder Problems が推薦する過去問がいい具合に苦しめてくるので時間が溶ける。ここ数日の睡眠不足はこれのせい。とても良い。


2019年10月14日 (月) ガソリンスタンドで見た注意書き。「給油中はエンジンを切りましょう」■思わず「え、そんなことができるの? 給油口を開けたあとですぐにキーを差し直してエンジンをかけるの?」と思ったのだけど、たぶん運転席周りのレバーでぱかっと開けられるのだろうなと気がついた。■プレス機なんかは両手で操作をしないと作動しないような仕組みになってるんじゃないかと思う。「両手操作式安全装置」というのがそうではないか。本の裁断に使っているカッターには「一人で作業するように」という注意書きがある。もともと片手で押し下げられるようなレバーではないので、そういう注意になっている。■給油口を鍵なしで開けられる車はなんと「便利」なんだろう。■最近のキーは鍵穴を必要としないみたい。そういう時代に合った車のインテリジェントさに期待してもいいのだろうか。実際どうなの?■アクセルを踏んだら自動でパーキングブレーキを解除しますよ、ってな「スマートさ」だけは知ってるんだけど。俺は信頼できない自分を縛るために信号停止のたび、渋滞中の一進一退のたびにサイドブレーキを引くんだけど、自動で解除されたら困るんだけど。


2019年10月12日 (土) ちょっとだけGOLFに走った (311 Byte / 60 ms / 1916 KB)」「悪ノリしたが空白を詰めただけでは変態ゴルファーの背が遠い (188 Byte)」からの派生。■俺は「可読性」という言葉を、そうとう眉に唾をつけて見ている。これが「表面的なこと」「主観的なこと」に不相応な大義名分を与えている気がするから。典型例が「条件演算子は可読性が~云々」。絵本しか読めない人間がすべきは決して、「じをよみなれないぼくにもわかるようにもっと *可読性* をたかめてください」と主張・要求することではない。早く読めるようになって最初に内容を議論できるようになるといいですね。がんばりましょう。■たまたま例に挙げたけど、俺は条件演算子が好き。理由もある>20181029。if が値を返さない C++ では使わずに const を徹底できないという理由もある。■俺は可読性が Easy を志向していると言っている。そのように使われがちな現実がある。それでは紛糾するし迷走するから、志向するのは Simple な何かにして、そこから可読性が生じるように仕向けるのが正しい順序ではないか。■Ich! Ich! Ich!■■■たまたま見つけた9年前に書かれた文章。「ソースコードの可読性や保守性:地方からの戯言:エンジニアライフ」■最後の方から引用。保守性については定見はないが、まったくその通りだと思う。「プログラムの組み方、という点においては、私は保守性や可読性というものを持ち出すのは避けるべきと感じています。ある人の基準がそのまま別の人に通じるとは限りません、むしろ経験や思想などが異なることの方がほとんどです。通じないことの方が多いでしょう。そのような状態で議論を続けるのはある種の押し付けでしかありません。それを分かったうえで議論を続けることが建設的ではないでしょうか。個人個人によって大きく意見が異なる保守性・可読性といった指標を用いるのではなく、何か別の伝わりやすく明確な基準、それが何かは非常に難しいかもしれませんが、レスポンスなどの比較的判断しやすい要素が必要なのだと感じます。」■同じ人からさらに。大いに共感する。「誰にでもわかるような仕事:地方からの戯言:エンジニアライフ


2019年10月06日 (日)

最終更新: 2020-05-06T23:26+0900

[AtCoder] AtCoder Grand Contest 039B問題 Graph Partition

もはや毎週恒例。たかだか B 問題に一日散々苦しんでおいてなんだけども、実行速度にハンデのあるスクリプトで、何の工夫もない総当たりを通されては、まったく釈然としない。

 最初の AC (AC / 1053 ms / 4476 KB)

Ds 関数1回は10数msで完了するみたい。Ds 関数1回2回でまあまあ AC (accepted) は出る。でも当てもんではないし、なんだかんだ残った WA (Wrong Answer) が潰せなくて総当たりにした結果、最長タイムが 1053 ms になったと、予期していた TLE ではなかったと。何か手を抜く洞察があれば。

Python でひとつだけ抜けた提出が 100 ms を切ってる。事前作成した実行ファイルを書き出して実行したり、コンパイル&実行したりの飛び道具は使ってないみたいだし、NumPy の文字も見えない。集合演算をよく使っている。ちょっとわかる気がしない。Python という時点で「for 文に else? これと同じ話?」>「なぜreturn -1にelseはいらないのか」というところから始まるのだが、それが主たる理由ではない。

 2番目のAC (AC / 849 ms / 4220 KB)

目新しいアイデアはない。ただ、「あるノードからあるノードへ移動可能かどうか」というデータを「あるノードから移動可能なノードの配列」へと事前処理しただけ。効果はめざましく、600 ms 台だった入力を処理する時間が軒並み2桁msに落ちた。たぶんほとんどのノード間に交通がなかったのだろう。

残る3桁msは3つだけで、それぞれ 100 ms、849 ms、840 ms。特に 800 ms 台の2つの入力がどういう特性を持っているのか(たぶん辺が多い密なグラフ)。対策したい。

 3番目のAC (AC / 74 ms / 2300 KB)

目新しいアイデアはない。Ds 関数の中心にある二重ループを効率的に回すことを考えただけ。ループが総体としてどのように歩を進めているかを低レベルで考える。そしてそれを縮約する方法を。やることは関数の仕様を変えない関数内部のコード変換なので、機械になったつもりで意味をはぎ取った記号(ビット列)を操作して、入力と出力を最短で結ぶイメージ。

Ruby は200ビット整数が普通に扱えて便利。その結果できあがったのが DsMax 関数なんだけど、副作用として……

  • ある点からその他の点への距離一覧(※Ds 関数の戻り値)の代わりに、最も遠い点までの距離しか得られなくなった。
  • -1 を返すパターンを検出できなくなった。

答えには最も遠い点までの距離しか使わないので1点目はいい。-1 パターンを検出するために、1回だけ Ds 関数を呼び出すことにして、それ以外で DsMax 関数を呼び出している。

いやあ、またしても Python に勝ってしまったなあ。(そういうコンテストではないし、コンテストは終了している。でもゴルフを楽しんでる人もいるし、なんでもいいじゃない)

あ、r -= sr ^= s の方が良かったかも。

 極まってるね! 提出 #7878842 (C++14 / 1 ms / 256 KB)

こんなん問題も見んと printf("%s", "答え"); してるんかと思うやん? 普通に二重ループを回してるんだよなあ。でも自分みたいに総当たりをするために三重ループになってしまってはいない。二重ループのある bfs を2回だけ呼び出して済ませてる。

この bfs 関数、すごく既視感があるんだけど、これを2回呼び出すだけで問題が解決する理屈が知りたいなあ。

 4番目のAC (AC / 26 ms / 2300 KB) と、その1文字違いのWA

ベースは2番目のAC。それの総当たりをやめて、2回だけ Ds 関数を呼び出すことにした。キモは、最初の呼び出しで引数に 0 を選んではいけない、ということ。それが WA と AC を分ける。たぶん 0 だと当たりを引いてしまうんだろうなあ。代わりに何を選ぶかは先の「極まってる」提出を参考にした。

正直言ってこれは入力依存のヒューリスティクスなので、時計を見て時間いっぱいまでランダムな試行を繰り返してまぐれ当たりを期待する手法と代わりがない。Ruby で一番に AC を獲得した提出がそういうものだった。

自分にとって真の提出は「3番目のAC」でいい。総当たりで間違いのない答えを求めても、3倍しかタイムが違わないのだから。

 5番目のAC (AC / 58 ms / 2044 KB)

3番目のACの改良版。DsMax 関数で -1 を返すパターンを検出できるようにして、Ds 関数を用済みにした。3重ループの総当たりでも、インチキの約2倍のタイムにまで迫ってきた。(でもこれをベースにインチキをしたら……)

 ちょっとだけGOLFに走った (311 Byte / 60 ms / 1916 KB)

短い方がすぐに読み終えられて理解が早いよね(大嘘)。でもね、コードはソルーションなのだから、理解するヒントは問題の中に存在している。問題を見て、答えを考えたら、コードが理解できる。それができないなら、どれだけ注釈があっても理解はできない。読みやすいコメントのおかげで理解した気になれるだけ。……というのが、20191002からリンクした「わかりやすさについて」からリンクした「C++で3秒だという人のコードを読んでいた」経験からの実感。

同じく20191002からリンクした「ドキュメントについて」に書いたが、ちょっとだけGOLFに走ったコードに足りないのは「基本がわかっている人間に向けた内部を理解する時間を節約するための勘所」だというのが自分の答え。そのために使えるのが意味のある変数名であり、プリミティブすぎるビット演算に意味を与える注釈であり、採用したアルゴリズムや入出力を説明する関数冒頭のコメントなどだ。

但し、但しだ。Easy はコードの性質ではないのだから、Easy なコードという概念はそれ単独では存在しない。猿でもわかる Easy を求めることは理解が伴わないので意味がない。猿を教育するのは自分の役割ではない。求めるのは、第一に「理解すること」。理解しない人間は読者ではないので。第二に「不明瞭な点を浮かび上がらせる質問」。第三があるとすれば「どう書いてあれば理解に要する時間が省けたかという提案」。Easy が主観だからこそ複数の視点に意味がある。

しかしその提案が「ヨーダ記法は目が受け付けないから NG」や「条件演算子は見慣れないから NG」や「unless は一旦 if に変換しないとわからないので NG」や「for や while に付く else は流れがよくわからないので NG」のレベルであれば合意はできないでしょうな。自分だって「大なり記号が混じると条件式が理解しにくくなるから右が正の数直線上に変数と数値を並べるようにしてほしい」とは言わない。そんなのは慣れや癖や縛りの類であり、自分にあるのと同じように他人にも馴染んだルールがあり、それが一部の判断を安全に短絡させ理解を早めるのである。ジャイアニズムには抵抗する。数を恃んで来ようものなら決裂は決定的だ。

俺は数が力だということを否定したいのだと思う(20181228, 20130228)。だから受け入れられなくなる。面白いよね、逆ではないんだ。否定するために受け入れないのではなく、受け入れられない現実が先にあって、その原理に対する理解があとから来る。これをこじつけと言う?

 悪ノリしたが空白を詰めただけでは変態ゴルファーの背が遠い (188 Byte)

るびまのゴルフ記事がめっちゃ楽しみだった。Rubyist Magazine 0021 号が第一回。著者の日記もゴルフ場もすでに知っていたけどゴルフに興味はなかった。でも解説記事は表層的な意味をはぎ取った言語への(身も蓋もない)理解が深まる楽しい読み物だった。さっき書いた「やることは関数の仕様を変えない関数内部のコード変換なので、機械になったつもりで意味をはぎ取った記号(ビット列)を操作して、入力と出力を最短で結ぶイメージ」にも通じる。「意味」に縛られて「実質」が見えないようでは、「抽象化」が覚束ないと思うのだ。これがまたさっき書いた、「変数名や注釈で意味を与えること」との間でバランスをとるもう一方の考え。

連載を読み直していたら最終回にいいことが書いてあった。「我々が努力して、そして楽しんでいる部分は、基本的なテクニックを抑えた上での膨大な時間を投下して行なう 論理的思考や発想の転換の勝負 なのです。」 基本的なテクニックっていうのが記号盛り盛りの変態的な見た目になってしまうアレ。アレの先にゴルフの真髄があるのだと。

しかし、ゴルフでも Python (191 Byte) に勝ってしまったのだなあ。>「すべての AC (コード長 昇順)

塗り替えるのが早い!!! (Python / 182 Byte)

燃えるね(160 Byte) タイムが約60msから約90msに増えてるのは、入力に対して String#to_i(2) を都度都度呼び出しているせい。ゴルフに魂を売ったようで心苦しい。パフォーマンスを追求する余録で無駄が削ぎ落とされたスクリプトが手に入った、という体でいたい。表記が変態的になるのは「本質」には影響しないから心が痛まないのだけど。

たぶん Perl 勢が参戦してきたらどちらも勝てないね。

ゴルフもまた沼なのか…… (146 Byte)

どっぷりはまっている(144 Byte)

最終更新: 2020-05-06T23:26+0900

[AtCoder] AtCoder Beginner Contest 138E問題 Strings of Impurity

Project Euler の人、という認識の人の日記でこの問題が触れられていた。参加していなかった回。「なんということもない問題」だが Python で TLE とのことなので、Ruby で挑戦。

 提出 #7886543 (AC / 432 ms / 10364 KB)

これが、Ruby の力!(違う)

ICache 変数抜きの提出では見事に(同じ)轍を踏みました>提出 #7886442 (TLE)。

ちなみに Ruby での最速タイムはちょうど3分の1の時間だった>144 ms。文字ごとに出現位置リストを作ってバイナリサーチらしい。魔法は無しか。

あるいはメモリをケチらずに文字列全長に渡って文字種ごとに次の出現位置を……、というのも魔法ではないな。オーバーヘッドでかいし。