ドキュメント整備にUNIX思想をぶち込んでAIに自動テストしてもらおう論
こんにちは、パスタそばです。
社会人になって1.5年。パスタもそばもあまり食べない食生活へとシフトするようになりました。 新生活を始める前もある程度自炊していたので、引き続きパスタを食べるという食生活が継続するのかなと思っていましたが、全然パスタを食べなくなってしまいました。
せっかくなので今日はパスタを食べようかなと検討していたところ、心の中の"リトルパスタ"の声が聞こえてきました。
パスタのときの栄養管理めんどーい! Where is タンパク質・ビタミン! ほぼ付け合わせの一品や二品絶対必要じゃん!あとベーコンとウインナー高い!
・・・元ネタのあの方*1と違い、随分俗世間的なことしか言わないリトルパスタに辟易しながらもその主張には同意せざるを得ません。 沖縄尚学優勝したしゴーヤチャンプルーにしましょう♪
What is 最近の非効率的なこと?
さて、よそ見運転はここまでにして最近社内で感じるちょっと非効率的なことについて考えてみようかと思います。
それは「作業の属人化・マニュアルの陳腐化」です。
おそらく読者の皆様の環境でも起こっていることだと思いますし、これは私の大学時代の研究室やサークルでもこのような現象が起こっていました。
渡されたマニュアルを見ると・・・おや、n年前の日付が書いてある。別の場所にも同じようなマニュアルがあるけど微妙に内容が違うぞ・・・!でも、先輩の話を聞いてみると全然やり方違っているじゃないか。(憤怒)さて、言われたとおりにコードを動かそうとすると・・・動作環境や環境変数がうまくセッティングされていないじゃないか!(大憤怒)
こんなこと、よくありますね。特に情報管理のツールが Word/Powerpoint/Excel -> 社内wiki のように変遷していたり、情報管理のルールが部署によって違っていると出社するのも億劫になってしまいます。*2
これに対する対策を考えるうえで、軽くドキュメント管理で調べてみたら、だいたい↓のような3項目が述べられる頻度が高いように見えました。(非核三原則の「持たず、作らず、持ち込ませず」という言葉とどことなく親和性を感じたので下記リスト形式としました。)
- (余計なドキュメントを)持たない
- (人力で)作らない
- (ルールから外れたドキュメントを)持ち込ませない
ソースコードの管理に当てはめてみると「使わないコードを作らない(UNIX思想)」「コードジェネレーターの使用(UNIX思想)」「Linter, Syntax check, コードレビュー, 自動テスト」といったところでしょうか。
そして、コードジェネレーターやLinter, Syntax check, コードレビュー, 自動テストというのは昨今の高性能なAIによって、自然言語に対しても似たようなことができるのではないかということを思うようになりました。ということで、
「AIが自然言語を上手に処理できるようになった現代だからこそ、ドキュメント整備にUNIX思想を持ち込み、AIによってUNIX思想を守っているか自動テストをしてもらいながら管理できるのではないか」
この主張?というか思いつきを皆様が議論してくれたらいいなというささやかな願いを込めて、この記事をインターネットの海に送り出したいと思います。
ではゴーヤチャンプルーの材料を買い出しにいくことにします。
無印良品のゲルインキボールペンとSARASAを比べてみた
こんにちは。パスタそばです。
あらすじ
私、実はムジラーとまではいかないものの、そこそこの無印良品ファンです。 というのも無印良品のデザイン哲学は、自分の好きな「シンプルイズベスト」という考え方に非常にマッチしております。
製品の役割や目的を考え、ユーザーがそれに集中するために余計な装飾を行わない・・・
素敵な考え方だなぁと思っております。
そんなこんなで無印良品のパスポートケースを購入したのですが、そのケースの中にボールペンを留めるため?のバンドがちょこんとくっついていることに気が付きました。
そこで無印のボールペンを買って、完璧なパスポートケースにしよう!と思い立ちました。
最近の無印良品はローソンとタッグを組んでいるらしく、ローソン店内でも無印良品の文房具や化粧品、ちょっとしたおやつなんかを購入することができます。 そんなわけで寒い中コンビニに出かけて無印良品のゲルインキボールペンだけを買ってきて、せっかくなのでその元?となったゼブラのSARASA CLIPと比較してみることにしました。
比較してみた!
外観
- 軸の太さはどちらも変わらない。
- 長さは無印の方が2~3mm程度長い。
- 素材感は無印はすりガラスのようなプラスチック。SARASAは透明のプラスチック+グリップ部はゴム。
- デザインの一貫性や余計な装飾の排除は無印の方が考えられている気がします。
書き味
- 滑りにくさはSARASAの方が優れています。逆に無印のボールペンはするすると滑っていきやすそうです。
- 書いた際の安定感はSARASAの方が優れている気がします。軸のぐらつきがより少なく、重量感もあるので「ボールペンを押さえつける」という力が必要ない感じです。
- インクはどちらもゲルインキらしく、くっきりとした美しい黒
- 書き味を個人的に言語化すると、無印は「あぁボールペンだなぁ」、SARASAは「高い製図用シャープペンシルっぽい」という感じでした。
個人的には、無印のボールペンはそれ単体で「美しいなぁ」と思うデザインで、ぐりぐりと自由にメモを取るときに使いたいですね。パスポートケースにはぴったりです。
一方、SARASA CRIPはさすが文房具メーカーが作るボールペンといったところ。純粋に仕事や勉強など、書類作業の相棒にするならこちらを選びたいところです。
英語ディスカッションが難しかったのでアマプラ見ます
こんにちは。パスタそばです。
さて、私事にはなりますが、最近イキって英語のグループディスカッション授業を履修しました(してしまいました?)。 研究では英語の文章を目にすることも多く、「意外とeasyなclassなんじゃないか笑」と自信を持っていましたが、心を粉砕されてしまいました。
自分以外のメンバーが全員留学生という中で、自分だけがポツンとコミュニケーションの孤島に取り残されてしまいました。 言いたいことを表現する英語が見つからず、他のメンバーの議論を黙って聞いているばかり(しかも3, 4割くらいしか理解できない)でした。
個人的に感じた英語のハードルは以下の通りです。
外国語訛りの英語を聞き取ることが難しい!特にフランス語訛りの英語は、イントネーションや単語の切れ目を認識できなくて喋っているアルファベットが分かりませんでした・・・
途中で知らない単語が出てくるとそこで理解がフリーズする!語彙力不足です。
相手の喋っている英単語は認識できるが、意味を認識できない!日本語でこの感覚を味わいたいときは、 行為無価値 - Wikipediaとかに目を通してみてください。この分野の専門知識がない私のような人にとっては、日本語だけど何言っているのか分からないという感覚に陥ると思います。
相手の喋っていることは分かるが、議論の流れを掴むことができない!話しているテーマが切り替わったり、各メンバーがどのような意見を持っているか、それについて誰が賛成・反対の意見を持っているのかを理解することが難しいです。
軽い雑談なら分かるし、自分も結構ペチャクチャ喋ることはできましたが、議論では「I can't understand what you said」と言われて心が折れかけたりして役立たず人間と化しておりました。
ということで授業中に「やばいやばい全然理解できないけど何か喋らなくちゃ、でも自分の発言で議論の腰を折っちゃったらどうしよう」みたいな感じで右往左往していたら、心優しい留学生から「アメリカの英語を字幕つけて見るといいよ」と笑顔で教えてくれました。*1
流石に自助努力もせずに相手に"easy English"ばかり求め続けるのも気が引けるので、早速帰ってからAmazon Primeでいつも見ている「相席食堂」の代わりに「マトリックス」を見ました。
発音を確認しようと一時停止をするたびに
ちょっと待てぃ!(例のSE)
ノブ「何を言うとる?」
大吾「地上に新しい言語が誕生しました」
(スタッフの笑い)
という会話が聞こえてきたような気がしましたが、英語音声・日本語字幕で完走いたしました。
とても面白かったです。
就職活動を終えてみて
随分冬眠していたね。
久しぶりです、パスタそばです。
前回の投稿からものすごく時間が経ちましたが、なんやかんやありつつも無事に大学・大学院と過ごし、何とか就職活動を終えることができました。 大学入学当初は、「これからAIの時代がやってくる。AIの研究者ならAIに仕事を奪われないから安泰だろう」というふんわりした心持ちでAI関係の職業を志していましたし、学部3年あたりまで自分はシステムエンジニアかwebエンジニアになっていくのかなぁと思っていましたが、6年後に選んだ就職先は外資系半導体企業でした。
今振り返ると随分面白い方向に人生は流れていったように思えますし、逆に自分の感性・性格がこの方向への人生を運命づけていたのかもしれません。 (まだ働き始めてもいないのに随分と偉そうな物言いですね)
自分は就職活動で何度も躓いた人間です。
学部時代に就職活動をやってみて、エピソードの弱さや面接の難しさに辟易して自分はどこにも就職できないんじゃないかと思ったこともありました。"ガクチカ"を作ろうとして趣味や授業に取り組もうと自主的に努力したものの、結局それをやり抜くことはできませんでした。また、自己分析もお粗末で、明らかに適正に合わない企業のインターンや本選考を受けていました。
そうです、私はSEになるほどコミュ力はないし、webエンジニアになるほどスクラム的に開発することが好きなわけでは無かったのです。
それでも、修士になってからは失敗経験を踏まえて、早期から動き出しましたし、これまで以上に自己分析に力を入れることで自分の適正や好み(内向的・実体のあるモノ作りが好き・SF世界のように新しい風景を世に生み出せる・専門性の高い仕事etc)を半導体業界に見つけることができました。
自分を半導体業界へ導いてくれた研究室との巡り合わせもあまりよいものではありませんでした。
学部時代、私は自分の身の振り方に迷っていました。大学の授業を頑張るべきか、サークルやアルバイトといった学外活動を頑張るべきか分からない時期でした。高校時代に得意だった数学が苦手になっていました。自分はSEにもwebエンジニアにもAI研究者にもなれない・・・。いつしか、メールをチェックするのも億劫になっていた時期でした。そんな時期に、研究室配属説明会のメールを見落とすのは必然でした。そんな中、たまたま自分が現在所属することになる研究室に流れ着きました。もう研究室配属説明会を開催する研究室が残り5つほどとなっていた時期でした。
それでも、学部時代に高レイヤの研究やwebアプリ制作活動を通じて自分のこの分野への適性の無さや情熱の不足を経験していたからこそ、あえて半導体・回路設計というゴリゴリの低レイヤの世界に飛び込むという選択をすることができました。
そして、それは最高の決断でした。
研究はとても大変でしたが、同時にとても楽しく、自分の適性を感じられるものでした。結構な大企業との共同研究も、自分の名前が入った特許申請も経験する機会を得ることもできました。そして、これは当然ガクチカとして採用させて貰いました。
内定を頂けた企業との巡りあわせも偶然的なものでした。
その企業の名前は、M1の頃に研究室で紹介された長期インターンシップ情報で初めて知りました。結構な大企業ですが、案外情報は出回っていませんでした。
とある就職情報サイトで調べてみると、ここ数年は年に1~2人採用するかどうかで採用活動を行わない年もあるような企業でした。合理的に考えればこのインターンシップには参加しない方が良いと思っていました。もし、自分が"タイパ"感覚に優れている要領の良い学生だったのなら、就活本番を迎える年に採用活動をするかどうかも分からない企業で数週間レベルの長期インターンを行うという選択はおそらくしなかったと思います。
それでも、憧れは止められませんでした。合理的ではない、そう思っていてもインターンに申し込みました。
インターンはとても素晴らしいものでした。その年は新卒の採用枠が設けられるという情報を会社の人から教えてもらいました。 そして、インターンが終わってからもLoveコールを送り続け、内定を頂くことができました。
何度でも立ち上がってやる。このチャンスを絶対掴みとってやる。
正直、この先の人生がどうなるか分かりません。
優秀な人材となるために勉強し続けないといけないことは分かっています。よい企業ですが定年まで残っていられるとは思っていません。自分も海外で生活したい、航空宇宙関係の仕事をしたいという野望も残っています。一方で、大学時代もそうであったように、社会人になってからも挫折したり失敗することから避けられるとは思っていません。
なにせ、自分はあまり要領の良い人間とは言えなさそうですからね。
それでも、様々な幸運に恵まれ自分の納得のいく就職活動を行うことができました。もし自分の名前のwikipediaのページが作られたとしたら、「大学編」だけでも結構なボリュームになるかもしれません。
私は常々、インターネットや本で見かける"就活体験記"の眩い輝きを苦手にしています。そんなに人脈はないし、あえての逆張りで無駄にしてきたチャンスも多いし、サークルでの活動は大したことないし、何らかの優勝経験も、大した資格もありません。そういうのを見ると自分がみじめに思えてきます。自分が無価値に思えてきます。
だからこそ、私と同じようなキラキラ系ではない学生を、過去の自分を勇気づけたくて。
最長増加部分列(LIS)の問題に4日間かかった件について
本日、とあるしょうもない事情で解く羽目になっていた問題を4日間かけて解くことができました。
ということで、おそらく全国の競プロerから鼻で笑われるはずですが、格闘した結果をさらします。
※本記事では onlinejudge.org の「10131 - Is Bigger Smarter?」の解法について言及します。ネタバレが嫌いな方はご注意ください。
どんな問題?
回答したのは onlinejudge.org の「10131 - Is Bigger Smarter?」という問題です。
問題としては、競プロ界では基本的な最長増加部分列(LIS)問題の応用形といった形です。
オーソドックスな解法としては、elephantをIQで降順にソートし、その後IQやweightが等しくならないようにweightの最長増加部分列を求めるといった具合だと考えられます。
問題を解き始めた当初、私もこの構想まではたどり着けていました(自慢)。しかし、最長増加部分列問題のアルゴリズム実装で事件は起こりました。
最長増加部分列(LIS)ってどう解くの?
最長増加部分列(LIS)問題のアルゴリズムを知らなかった私は、もちろんgoogleや蟻本で調べたわけですが、悩み初めてから3日経つまで以下のことに気が付きませんでした。
最長増加部分列(LIS)の長さを求めるためには動的計画法が利用できるが、実装方針としては2通りある。
解法1. 「長さ i の増加部分列の末端要素をなるべく小さくする」方針
(例:最長増加部分列(LIS)の長さを求める - Qiita)
解法2. 「配列の j 番目の要素が増加部分列の末端であると仮定したとき、増加部分列が最も長いものを見つける」方針
(例:https://yukicoder.me/wiki/longest_increasing_subsequence)
そして、肝心の最長増加部分列は解法2でしか求められなかったということに・・・・
1つ目の解き方
先ほど紹介した解法1は、二分探索を用いることで計算量 O(nlogn) で計算できますが、最長増加部分列の「長さ」しか求めることができないということを理解できていませんでした。
例えば、{1, 3, 5, 2}という配列の最長増加部分列を1つ目の解き方で解くと、dpテーブルは
| i | 0 | 1 | 2 | 3 | 4 |
| dp[i] | 1 | 2 | 5 | INF | INF |
となり、最長増加部分列の長さである3は求まるものの、dpテーブルは{1, 2, 5}となっており、正しい最長増加部分列を求めることができません。
私は「10131 - Is Bigger Smarter?」を解く際に、こちらの方法で挑んでしまい時間を大幅ロスする結果になりました。
2つ目の解き方
解法2は、計算量 O(n*n) とやや低速になるものの、配列のi番目の要素を末端に持つ増加列の最大長を保存するテーブルmax_lengthと自分の要素の親を保存するテーブルparentを設けることで、最長増加部分列とその長さの両方を求めることができます。
例えば、a ={1, 3, 5, 2}という配列の最長増加部分列を2つ目の解き方で解くと、dpテーブルは
| i | 0 | 1 | 2 | 3 |
| a[i] | 1 | 3 | 5 | 2 |
| max_length[i] | 1 | 2 | 3 | 2 |
| parent[i] | null | 0 | 1 | 0 |
となり、max_lengthの最大の要素が3であることから、部分増加列の最大長は3であることが分かります。 また、parent[2] → parent[1] → parent[0] → null と後ろからたどることで最大増加部分列の具体例を求めることができます。
反省
貧弱な語彙力と文章力から成る雑記事でしたが、この記事が誰かの役に立つことを願っております。
皆様の競プロ人生に幸あれ。
「CPUの創りかた」の感想とおすすめの使い方?
目次
読んだ本
今回紹介する本はコチラっ!
名著として名高い「CPUの創りかた」(著 渡波郁/マイナビ出版)です。
この本を読んだ経緯としては、
- 自分の卒業研究がFPGAを利用した通信?の研究になりそう
- でもFPGAのことほとんど知らない・・・
- FPGAの勉強の前に、そもそもCPUってどんな仕組み?
(情報系学生の面汚し) - CPUについて理解するために、まずは名著として名高い入門本を読んでみよう
こんな流れです。
流れが適当すぎるような気もしますが、とりあえず「CPUの創りかた」を読破したので、自分の復習も兼ねた内容紹介などを行っていきたいと思います。
ちなみに、CPUについてもっと深く理解するためには、「CPUの創りかた」を読んだ後に以下の本などに進むとよさそうです。ぜひご検討ください。
本の内容と感想
本書のコンセプトとしては、「シンプルなCPUをICを使ってお手軽に作ろう」というものです。"お手軽"とか"初歩"とか"基本原理"というキーワードの通り、会話テイストの文章、かわいいイラスト、実際に動作するCPUが作れることが印象的でした。
一方で、技術的な到達レベルも高く、最終的に論理回路を使ってCPUの各部品(デコーダー、プログラムカウンタ、ALU、レジスタ)やメモリ(ROM)を作れるようになるという素晴らしいものです。
この本をオススメする人
この本をオススメする人は以下に当てはまるような人です。
- コンピュータの入門書が欲しいが、お堅い表現が嫌い
- 抽象的な話ではなく、実際に手を動かしながら理解したい
- CPUやメモリが論理回路で作れることは知っているが、作り方は知らない
- パソコンは01で動くというものの、もっと電気的な話が知りたい
まあ、すべて私のことなんですがね。
少しでも当てはまる場合は、ぜひ読むことをお勧めします。
この本をもっと生かすために・・・
以下の知識があると、本書をより楽しめそうです。
全般
電気的なことを扱うため、オームの法則やコンデンサーの仕組みなどを抑えておくとよさそうです。
私は本書の理解にあたって、高校物理の参考書にあった「導線でつながれているところは等電位!!!」みたいな言葉に救われました。
また、ブラウザ上でデジタル回路のシミュレータがあるため、目で追うのが大変な場合は使ってみることをお勧めします。
チャプター6-2
本書ではアセンブリがいきなり登場しますが、プログラムのコンパイル時に
という風に変換されることを知っておけば、アセンブリというものに戸惑わないかもしれないです。 教材としては、以下の記事なんかがよさそうです。
bit全探索でやらかしたメモ(個人用)
概要
c++でbit全探索を実装しようとして、個人的に引っかかったところを紹介します。
問題個所
AtcoderさんのABC190のC問題(Bowls and Dishes)を解いていたときに問題が発生しました。
もともと、int型2次元配列 Putting_table[N][2] に対してbit全探索をするつもりでした。
つまり、想定していた動作としては N=3 のとき、
====== bit: 0 Putting table [0][0] Putting table [1][0] Putting table [2][0] ====== bit: 1 Putting table [0][1] Putting table [1][0] Putting table [2][0] ====== bit: 2 Putting table [0][0] Putting table [1][1] Putting table [2][0] ====== bit: 3 Putting table [0][1] Putting table [1][1] Putting table [2][0] ====== bit: 4 Putting table [0][0] Putting table [1][0] Putting table [2][1] ====== bit: 5 Putting table [0][1] Putting table [1][0] Putting table [2][1] ====== bit: 6 Putting table [0][0] Putting table [1][1] Putting table [2][1] ====== bit: 7 Putting table [0][1] Putting table [1][1] Putting table [2][1]
という感じでPutting tableの要素にアクセスすることを意図していました。
問題のコード
以上の想定動作に対して、当初は
for (int i = 0; i < 3; i++) {
Putting_table[i][bit & (1 << i)]
}
という実装をすればよいものだと思っていました。
しかし、この実装を行うと
====== bit: 0 Putting table [0][0] Putting table [1][0] Putting table [2][0] ====== bit: 1 Putting table [0][1] Putting table [1][0] Putting table [2][0] ====== bit: 2 Putting table [0][0] Putting table [1][2] Putting table [2][0] ====== bit: 3 Putting table [0][1] Putting table [1][2] Putting table [2][0] ====== bit: 4 Putting table [0][0] Putting table [1][0] Putting table [2][4] ====== bit: 5 Putting table [0][1] Putting table [1][0] Putting table [2][4] ====== bit: 6 Putting table [0][0] Putting table [1][2] Putting table [2][4] ====== bit: 7 Putting table [0][1] Putting table [1][2] Putting table [2][4]
という出力結果になってしまい、最悪の場合 Segmentation Fault が起きてしまいます。
この理由は、例えばbit=7のときを考えると、
7&(1<<0) は バイナリで考えると、"111"&"001" という意味になり 1 が出力される一方、
7&(1<<1) のときは、"111"&"010" という意味になり 2 が
7&(1<<2) のときは、"111"&"100" という意味になり 4 が出力されてしまうからです。
どうすりゃよかったの?
先ほどのソースコードに少し手を加えて
for (int i = 0; i < 3; i++) {
Putting_table[i][bit & (1 << i) ? 1 : 0]
}
とすればよさそうです。
c++ ではint型 0 はbool型 False に対応し、
int型 非0は bool型 True に対応するので、
それらを生かして三項演算子を使う感じですね。
追記
以下のサイトを見たところ、安易にint型 0 はbool型 False に対応し、int型 非0は bool型 True に対応すると決めつけてしまうのは良くなさそうですね。 www.pc-gear.com
