修論終わり
- 修論が終わった。
論文を無事書き終わることができた。
ひとえに僕を支えてくれたみんなのおかげだと思う。
僕の研究の結論は、ここではそっと胸に秘めておくとして、
研究をしていく中で改めて下記の言葉の大切さを実感している。
Think different. 自分が天才だと思ったことはないが、長年、変な人を貫いた覚えはある。
— Yukihiro Matsumoto (@yukihiro_matz) 2011, 12月 21
っと、まぁ意識高いキラキラ修士な匂いがプンプンする文面であるが、個人的には色々と思うところがあり、もう少し研究をしてみたいなっと思いつつ、残りの作業(海外論文へ投稿)は教授に任せることにした。データをくれといわれたときに吐き出す作業には協力するように言われているので、社会人になっても若干の引き継ぎは残るものの、こういうときには指導教官の偉大さを感じる次第。(まぁ、他の先生たちもホントすごい人ばっかだったけど。。。)
あまり特定されない範囲で書くと、自分が比較的新設の大学院に入学するとなったとき、正直、あまり教育方針には期待していなかった。大体、できたばっかりなんだから好きなこと勝手にやろうと思って入った節がある。しかし、それぞれ関連が薄く、つながりが見えにくいカリキュラム(すいません)をこなしていく中で、自分の中では少なくとも点と点がつながった感触があった。きっと、この感触は他の後輩も感じると思う。そこに、論文を書けるだけの新しい形が潜んでいる気がする。
おそらく今の時代に古典的な数学(微分幾何学とか?)を学んで成果を出すのは難しいだろう。現に僕の学部のころの微分幾何学の先生は、学ぶだけでおなかいっぱいになってる印象だった。それに比べて、計算機科学に近しい分野をやってる人は今最も楽しい思いをしているはずだ。(研究に興味があれば)
中学生くらいの頃、歴史の教科書に載ってる中世の人の髪型を見て笑う人がいたが、僕は正直、今の時代にいる人もその人たちと変わらないと思う。自分たちが、普遍的なポジションにいると錯覚してしまいがちだが、今という限られた時代の様式に従って僕たちは生きてる。僕らの服装も時代とともに変わっていく。今の時代に反発してバッハみたいなカツラをかぶる人やちょんまげを常備整えている人はおそらくほとんどいないだろう。その時代の人たちを笑う行為は、ダブルスタンダードに近い。(大げさだなぁ
っと、まぁ系譜学みたいなことをいってもあれなんだが、何がいいたいかというと、僕たちは、タイムマシーンがない以上、この時代を生きるしかないわけで、この時代に最適化する必要があるだろうということだ。それは、やったほうがいいと思う。(頑固な人は変えなくていいけど)そのほうがきっと今の流れに乗って先のほうまで景色が見えると思う。今まではみんなに見えなかった景色。それが、今でいうところの計算機科学、ひいてはバイオや、宇宙工学なんだろうと思う。けど、あまりにも短期的に最適化する必要はない。それこそ、今、10年前のプログラミング言語を使う人がどのくらいいるか、みんながあとどれくらいクラウド!クラウド!って言ってるか、データサイエンスって言ってるかは僕にはわからないけど。そのワードを言ってる人たちは、きっとその根底にある大事なことを学んでほしいから新しいキーワードを紹介して、若い人たちを釣ってるんだと思う。だから、そういうのはきっかけであればいいし、普遍性はきっとすぐそばに横たわってると思う。(ポエム終わり
クラスにイテレータの性質を付加する
- クラスと辞書の関係
ちょっと前の記事で紹介したとき、pythonのクラスはデフォルトとしてイテレータとして使用できていませんでした。今回も基本的なことですが、イテレータを定義する話です。
>>> class _: pass >>> list(_) Traceback (most recent call last): File "<pyshell#26>", line 1, in <module> list(_) TypeError: 'type' object is not iterable
「オブジェクトはイテレータではありません。」そうか、じゃあ定義しよう。たとえば、辞書型みたいに整形して、属性をイテラブルに呼び出したりできるクラスがほしいな。。と思っていたら、できるみたいです。
class Person: def __init__(self, age, sex, name, subject): self.age = age self.sex = sex self.name = name self.subject = subject def __iter__(self): for k, v in self.__dict__.items(): yield (k,v) if __name__ == '__main__': p = Person(20, "male", "John Smith", "computer simulation")
- 実際に動かしてみた
これでクラスの定義ができました。実際に動かしてみましょう。
>>> p <__main__.Person object at 0x0000000003924518> >>> p.__dict__ {'subject': 'computer simulation', 'sex': 'male', 'name': 'John Smith', 'age': 15} >>> [i for i in p] [('age', 15), ('subject', 'computer simulation'), ('name', 'John Smith'), ('sex', 'male')] >>> [print(k+":",v) for k,v in p] subject: computer simulation sex: male name: John Smith age: 15 [None, None, None, None]
クラスの属性は辞書型で保存されているようです。それを用いてジェネレータ関数を使用し__iter__を定義してみました。ジェネレータをまわすときにはyieldを使いましょう。もしreturnで定義してしまうと
#変更したクラスの箇所 def __iter__(self): for k, v in self.__dict__.items(): #yield (k, v) return (k, v) >>> [i for i in p] Traceback (most recent call last): File "<pyshell#45>", line 1, in <module> [i for i in p] TypeError: iter() returned non-iterator of type 'tuple'
イテレータではなく、普通にタプルを返すので、イテレータをちゃんと返せとエラーが返ってきます。
- そもそも論
初めから__iter__や__dict__があるならあるいはもっと基本的な__iter__, __dict__の定義があるんじゃないだろうか。そうなんです。たとえば、これだと
class A: def __init__(self,x,y): self.x = x self.y = y >>> a = A(1,2) >>> a <__main__._ object at 0x000000000376EE48> >>> a.__dict__ {'y': 2, 'x': 1}
辞書はもともと入っているので、先ほどのようにイテレータを定義せずとも辞書は出せたわけです。当たり前といえばそうなんだけど
>>> help(a) Help on A in module __main__ object: class _(builtins.object) | Methods defined here: | | __init__(self, x, y) | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
ヘルプにもちゃんと初めから書いてあるし。。じゃあ、__iter__はあるのかというと
>>> help(a.__iter__) Traceback (most recent call last): File "<pyshell#97>", line 1, in <module> help(a.__iter__) AttributeError: 'A' object has no attribute '__iter__'
ない。だったら、書けばいいのだが、iterだけを用意したらいいのかというとそうでもなくて、next()関数を定義してやることで正常に動かせるようです。
(引用)
Pythonの技法:ジェネレータを用いた遅延リストの構築 - builder by ZDNet Japan
Python のジェネレータ (1) - 動作を試す | すぐに忘れる脳みそのためのメモ
Python のイテレータ (3) | すぐに忘れる脳みそのためのメモ
エキスパートPythonプログラミング(1) イテレータ、ジェネレータ、ジェネレータ式 - 作業記録/備忘録(仮)
Pythonのイテレータとジェネレータ - Qiita
ジェネレータ (プログラミング) - Wikipedia
TypeError: 'int' object is not iterable
プログラミングと暇つぶし Python リストを見ていたら、「pythonにてstrの数字とintの数字を取り込んで全部int化されたリストを作りたい。けど、エラーがでてうまくいかない」って書いてあるところでなんか引っかかった。ブログで言及されているTypeError: 'int' object is not iterableは今まで見たことがないエラー。リスト関数list()ってよくよく考えるとイテレーターなものしか飲み込まないんですね。知らんかった。
で、こういう時ってmapなのかなぁっと思って書いた。*1
>>> [1, 2]+list(map(lambda x:int(x),list("34"))) [1, 2, 3, 4]
うーん、可読性悪いな。
- 補足
どういったものがイテレータで、どういったものが違うのか具体例を三つほど挙げます。数字やクラスはどうもダメみたいです。文字はイテレータですね。クラスについては、別途、イテレータとしての定義が可能です。
>>> list("a") ['a'] >>> list(1) Traceback (most recent call last): File "<pyshell#22>", line 1, in <module> list(1) TypeError: 'int' object is not iterable >>> class _: pass >>> list(_) Traceback (most recent call last): File "<pyshell#26>", line 1, in <module> list(_) TypeError: 'type' object is not iterable
- おまけ
やっぱ内包表記がシンプルですよね。
>>> [1,2]+[int(x) for x in "34"] [1, 2, 3, 4]
*1:python3のmapはlistを返すことはありません。変換しましょう
java to python
- Cがエラーを吐いたとき
僕が研究で使用しているシミュレーションのプログラムはCで記述されている。このプログラムでは、グローバル変数をマクロ(#define)で記述しています。こうしておいてパラメータの部分だけヘッダーファイルにまとめてから、pythonで
1.ヘッダーファイルのマクロを書き換える
2.コンパイル&実行
ってなことをやっているんですが、たまにエラーを吐くことがあるんですね。書き換え実行のスパンが短すぎるのだろうなと考えてsleepコマンドをかませるというのもやってみたのですが、効果はまちまち。コンパイルエラーしたら、マクロを書き換える前のパラメータでファイルが実行されているため、同じデータが記述されてしまいます。
- javaのコードを久しぶりに拝見
上記のような「データの中にまれに、同じ情報(ゴミ)が入ってる。除くコードを書いてみよう」ってことで、まずは、隣の要素と比較して出力するようなものを自分で書かずに適当にググる。ググったらyahoo!知恵袋で紹介されていた。なんだあるじゃないかってことで、javaのコードを見て、pythonに書き直してみました。
import java.util.ArrayList; import java.util.List; public class Duplicate { public static void main(String[] args) { String[] ss = {"b", "b", "a", "a", "c", "c"}; List<String> ls = new ArrayList<String>(); for (int i = 0; i < ss.length; i++) ls.add(ss[i]); String prev = ls.iterator().next(); List<String> ret = new ArrayList<String>(); ret.add(prev); for (String e: ls) { if (!prev.equals(e)) ret.add(e); prev = e; } System.out.println(ret); } }
長いですね。てか、ls.iterator().next()とかif (!prev.equals(e))の辺りはjavaってこういうメソッド用意されてるんだなと。以下、書き直したpythonのコードです。
ls = ["b", "b", "a", "a", "c", "c"] prev = next(iter(ls)) ret = [prev] for e in ls: if prev != e: ret.append(e) prev = e print(ret)
いや、まてよ。next(iter(ls))の下りってls[0]でよくね?っと思って書き直した。
ls = ["b", "b", "a", "a", "c", "c"] prev = ls[0] ret = [prev] for e in ls: if prev != e: ret.append(e) prev = e print(ret)
厳つかったjavaのコードだったが、大したことしてないな、これ。
hyクイックスタート
いつものようにTwitterでスルスルと時間を浪費していると、reddit.comだったかの海外の記事が回ってきまして、Hyというpythonのライブラリが使えるlispの存在を知り、ちょっと気になってクイックスタートから読んでました。以下、つたない導入手続き。
- HYをソッコーで手に入れる手順
Karen Rustadさん、Cuddlesをありがとう
Quickstart — hy 0.10.1 documentation
0.pythonをインストールする。(pathも通そう)
Welcome to Python.org
環境変数PATHの設定 - 環境設定と動作確認 - Pythonインストールと環境設定
1.pipを入れる。(場合によってはpythonにはじめから入ってるよ)
pipの使い方 (2014/1バージョン) — そこはかとなく書くよん。
2.お手元のterminalかcmdにpip install hy と入力(殆どの人はこれだけで使える)
3.インストールが終わったらhyと入力してREPL発動。
4.以下の例を打ち込んでみよう
=> (print "Hy!") Hy! => (defn salutationsnm [name] (print (+ "Hy " name "!"))) => (salutationsnm "YourName") Hy YourName!
5.Ctrlとdを押せば終了するよ
6.オーマイゴッド!すごいや、hyのプログラムが書いてみたいなぁ…
7.選ばれしエディタ(sublimetextでもメモ帳でもいいゾ)を開いて以下を書き込もう。
(print "I was going to code in python syntax, but then I got hy.")
8.furuegoe.hyで保存しよう。
9.terminalかcmdにhy furuegoe.hyと打ち込もう。
10.過呼吸にならないように深呼吸しよう。
11.やがて、君はクッソ汚い笑みを浮かべながら姿を消してしまい、筆舌に尽くし難い行動をとるようになる。
hy/quickstart.rst at master · hylang/hy · GitHub
*1:初めに申しておきますが、懐メロ邦楽とは関係ありません
数学の予想
- コラッツ予想
世の中には未解決の問題が数多存在する。今回紹介するものは、僕のようなアマチュアにも触れやすい、問題はシンプルだが難しい問題、コラッツ予想と呼ばれるものである。
- どんな予想か
コラッツ予想についてくわしく知りたい人はwikipediaでも読んでもらいたい。
コラッツの問題 - Wikipedia
で、ここでも軽く触れると、
ある自然数を用意する。次の操作を繰り返す。
・2で割りきれる数は2で割る。
・2で割れないときは3倍して1足す。
これを繰り返すだけで、1に必ずたどり着く。
というルールである。学部の頃はこれを手でかなり計算して、印刷用紙をセロテープでつなぎ合わせ、樹形図を書きなぐって、樹形図の枝が分岐する数の特徴について色分けをして、どのような特徴があるのか調べていた。今思えば、なんて原始的なことをしていたんだろう。本気で予想を解こうと目の色を変えていたのだろうか。けど、すごく楽しくて、今でも樹形図はどこかに保管されているはずである。
久々にpythonで書こうものなら、いとも簡単に関数を書くことができる。(勿論、他の言語でも簡単)
def col(x): print(x) while x >1: if x % 2 == 0: x = int(x/2) else: x = 3 * x + 1 print(x)
是非、皆さんもこの数の不思議を体験してもらいたい。ニュルニュルと数字が出力されるが、最終的には必ず1が出力されて止まってしまう。
>>> col(19999999) 19999999 59999998 29999999 89999998 44999999 134999998 67499999 202499998 101249999 303749998 151874999 455624998 227812499 683437498 341718749 1025156248 512578124 256289062 128144531 384433594 192216797 576650392 288325196 144162598 72081299 216243898 108121949 324365848 162182924 81091462 40545731 121637194 60818597 182455792 91227896 45613948 22806974 11403487 34210462 17105231 51315694 25657847 76973542 38486771 115460314 57730157 173190472 86595236 43297618 21648809 64946428 32473214 16236607 48709822 24354911 73064734 36532367 109597102 54798551 164395654 82197827 246593482 123296741 369890224 184945112 92472556 46236278 23118139 69354418 34677209 104031628 52015814 26007907 78023722 39011861 117035584 58517792 29258896 14629448 7314724 3657362 1828681 5486044 2743022 1371511 4114534 2057267 6171802 3085901 9257704 4628852 2314426 1157213 3471640 1735820 867910 433955 1301866 650933 1952800 976400 488200 244100 122050 61025 183076 91538 45769 137308 68654 34327 102982 51491 154474 77237 231712 115856 57928 28964 14482 7241 21724 10862 5431 16294 8147 24442 12221 36664 18332 9166 4583 13750 6875 20626 10313 30940 15470 7735 23206 11603 34810 17405 52216 26108 13054 6527 19582 9791 29374 14687 44062 22031 66094 33047 99142 49571 148714 74357 223072 111536 55768 27884 13942 6971 20914 10457 31372 15686 7843 23530 11765 35296 17648 8824 4412 2206 1103 3310 1655 4966 2483 7450 3725 11176 5588 2794 1397 4192 2096 1048 524 262 131 394 197 592 296 148 74 37 112 56 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
まぁ、何がしたかったって、スゲー長いブログの記事にしたかったっていうね。
続・リスト内包表記
- Python文法詳解買っちゃった
Amazon.co.jp: Python文法詳解: 石本 敦夫: 本
python文法詳解発売されたので早速買ってみました。p.81の4.2.2のリスト内包の欄にて、次のような記述を見つけたのでメモ。こんなこともできたんですね。
>>> L = [(1,'a'),(2,'b'),(3,'c')] >>> [c*i for i,c in L] ['a', 'bb', 'ccc'] >>> L = [(1,2),(3,4,5),(6,7,8,9)] >>> [car*sum(cdr) for car,*cdr in L] [2, 27, 144]
car, cdrという変数名になっているのはLispっぽいですね。*を付けることで残りのシーケンスを指すポインタ(?)として機能しています。
ちょっとLispで書いてみましょう。schemeの教科書なら一番初めに載ってる例です。
#lang racket > (car '(1 2 3 4)) 1 > (cdr '(1 2 3 4)) '(2 3 4)
(最近はracketでschemeも勉強しています。racketもとい、scheme, Lispに興味がある人は、こちらのURLへどうぞ)
いつ通りの書き方も載せておきましょう。添字(そえじ)が見やすい人はこちらでどうぞ。
>>> L = [(1,'a'),(2,'b'),(3,'c')] >>> [t[0]*t[1] for t in L] ['a', 'bb', 'ccc'] >>> L = [(1,2),(3,4,5),(6,7,8,9)] >>> [t[0]*sum(t[1:]) for t in L] [2, 27, 144]
- 何か違いはあるの?
(car,cdr)型と添字型。この二つの表記は全く同じ結果を出力するのでしょうか?どうやら、少しだけ違いがあるようです。
>>> L = [(1,2),(3,4,5),(6,7,8,9)] >>> [t[0]*t[1:] for t in L] [(2,), (4, 5, 4, 5, 4, 5), (7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9)] >>> [car*cdr for car,*cdr in L] [[2], [4, 5, 4, 5, 4, 5], [7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9]]
今度は、本に載っていた例を勝手に書き換えた、というかsum()を抜いた例です。よく見ると、片方はtuple型ですが、もう片方はlist型です。(そもそも、掛け算とポインタが入り混じった内包表記はよろしくないかもしれませんが。)なぜこうなるのかというと、
>>> a,*b = (1,2,3) >>> a 1 >>> b [2, 3]
こうなってるんでした。つまり、タプル(tuple)はこの(car,cdr)型にした途端にリスト(list)へと形を変えていたんですね。