修論終わり

論文を無事書き終わることができた。
ひとえに僕を支えてくれたみんなのおかげだと思う。
僕の研究の結論は、ここではそっと胸に秘めておくとして、
研究をしていく中で改めて下記の言葉の大切さを実感している。

っと、まぁ意識高いキラキラ修士な匂いがプンプンする文面であるが、個人的には色々と思うところがあり、もう少し研究をしてみたいなっと思いつつ、残りの作業(海外論文へ投稿)は教授に任せることにした。データをくれといわれたときに吐き出す作業には協力するように言われているので、社会人になっても若干の引き継ぎは残るものの、こういうときには指導教官の偉大さを感じる次第。(まぁ、他の先生たちもホントすごい人ばっかだったけど。。。)

 あまり特定されない範囲で書くと、自分が比較的新設の大学院に入学するとなったとき、正直、あまり教育方針には期待していなかった。大体、できたばっかりなんだから好きなこと勝手にやろうと思って入った節がある。しかし、それぞれ関連が薄く、つながりが見えにくいカリキュラム(すいません)をこなしていく中で、自分の中では少なくとも点と点がつながった感触があった。きっと、この感触は他の後輩も感じると思う。そこに、論文を書けるだけの新しい形が潜んでいる気がする。

 おそらく今の時代に古典的な数学(微分幾何学とか?)を学んで成果を出すのは難しいだろう。現に僕の学部のころの微分幾何学の先生は、学ぶだけでおなかいっぱいになってる印象だった。それに比べて、計算機科学に近しい分野をやってる人は今最も楽しい思いをしているはずだ。(研究に興味があれば)

 中学生くらいの頃、歴史の教科書に載ってる中世の人の髪型を見て笑う人がいたが、僕は正直、今の時代にいる人もその人たちと変わらないと思う。自分たちが、普遍的なポジションにいると錯覚してしまいがちだが、今という限られた時代の様式に従って僕たちは生きてる。僕らの服装も時代とともに変わっていく。今の時代に反発してバッハみたいなカツラをかぶる人やちょんまげを常備整えている人はおそらくほとんどいないだろう。その時代の人たちを笑う行為は、ダブルスタンダードに近い。(大げさだなぁ

 っと、まぁ系譜学みたいなことをいってもあれなんだが、何がいいたいかというと、僕たちは、タイムマシーンがない以上、この時代を生きるしかないわけで、この時代に最適化する必要があるだろうということだ。それは、やったほうがいいと思う。(頑固な人は変えなくていいけど)そのほうがきっと今の流れに乗って先のほうまで景色が見えると思う。今まではみんなに見えなかった景色。それが、今でいうところの計算機科学、ひいてはバイオや、宇宙工学なんだろうと思う。けど、あまりにも短期的に最適化する必要はない。それこそ、今、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クイックスタート

  • hyを始めよう*1

いつものようにTwitterでスルスルと時間を浪費していると、reddit.comだったかの海外の記事が回ってきまして、Hyというpythonのライブラリが使えるlispの存在を知り、ちょっと気になってクイックスタートから読んでました。以下、つたない導入手続き。

  • HYをソッコーで手に入れる手順

f:id:kerorosho-tai:20141124020023p:plain
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へどうぞ)


The Racket Language

いつ通りの書き方も載せておきましょう。添字(そえじ)が見やすい人はこちらでどうぞ。

>>> 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)へと形を変えていたんですね。