PyQt4 で簡単GUIプログラミング

インストールは

brew install pyqt

その後,PYTHONPATHの設定

export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH

参考:No module named PyQt4 after brew install

Hello world!!

import sys
import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui
def on_click():
 print("Hello World!")
def main():
 app = QtGui.QApplication(sys.argv)
 main_window = QtGui.QMainWindow()
 hello_button = QtGui.QPushButton("hello world!")
 hello_button.clicked.connect(on_click)
 main_window.setCentralWidget(hello_button)
 main_window.show()
 app.exec_()
if __name__ == '__main__':
 main()

ウィンドウが現れて,ボタンをクリックするたびに,ターミナルに

hello world!

と表示される.

広告

Pythonで巨大な階乗を求めた話

皆さん,元気にPythonistaしてますか〜?

Project Eulerとかいう数学力を試すコーディング能力を試すサイトで,

僕はPythonでチマチマ解いてます.

その中で,並列処理計算がちょっと気になったので,調べたついでに具体例で説明備忘録できたらいいな,と思います.(インタプリタで並列化とか意味不明すぎる,とかいうツッコミはなしでww)

具体例とは,ズバリ,タイトルにもあるように「階乗」です.

それも,巨大な階乗です.100000!にしましょう.

では,階乗を求めるコードを書いてください.

def Factorial_(integer) : 
 return 1 if integer == 0 else integer * Factorial(integer - 1)

確か,僕が学部の時,最初に習ったのはC言語だったのですが,

再帰関数の例でこんなのをやりました.でも,これで階乗を求めては

ダメです!

理由は,再帰の繰り返しであばばー,となるからです.

僕は,このコードを例に出すのは情報学演習の悪しき風習だと思うのですが,どうなんでしょう.教える側の詳しい事情,歴史,慣習は知りません.

実際,上のコードを100000!でやると

再帰回数を超えました

とエラーが出ます.Pythonのデフォルトの再帰限界は1000回だからです.

仕方ないので,積を格納する変数productを用意して

def Factorial(integer) : 
 product = 1
 if integer == 0 : return 1
 for num in range(1 , integer + 1):
 product *= num
 return product

みたいにします.

この2つのコードによる,(再帰限界を越えない程度の)998!はPython2.7,MacBookAir(Mid 2011 model)で

(前者) Factorial_(998) 0.762ms
(後者) Factorial(998)  0.586ms

となります.なお,時間の計測は

import time
 start = time.clock()
 Factorial(998)
 end = time.clock()
 print(str((end - start) * 1000) + 'ms')

のように雑に求めましたことを激白します(timeitは使っていない)

しかし,それでも100000!の階乗には関数Factorialで

Factorial(100000) 5037.811ms

5秒もかかります.

そこで並列化しました.簡単です.

MBAは4コアなので,以降4コアで説明すると,

100000!=(100000\times 99996 \times \cdots \times 4)\times (99999\times 99995\times \cdots \times 3)\times (99998 \times 99994 \times \cdots \times 2)\times (99997 \times 99993 \times \cdots \times 1)

とすればいいだけですよね!?

…実装しました.

import multiprocessing
import operator

c = multiprocessing.cpu_count()

def p_fac(n) : 
 product = 1
 if n == 0 : return 1
 for num in range(1 , n + 1 , c):
  product *= num
 return product

def p_Factorial(n) : 
 p = multiprocessing.Pool()
 return reduce(operator.mul , p.map(p_fac , range(n , n - c , -1)) , 1)

(間違いがあることが指摘されています)

cにはコア数が格納されます.僕のMBAですと4です.

p_facはcおきに数字を飛ばして階乗もどきを計算します.n!!!!ってことですね.

最後のp_Factorialでは,

p = multiprocessing.Pool()

で,プロセスのプールを作成します.

次の

reduce(operator.mul, ~)

は,~ に来るリストを全部積を取るだけです.

和だったらsumでやってくれるのに,積に相当するのがこんなのしかなくて,Pythonの仕様は???です.

そして,

p.map(p_fac , range(n , n - c , -1)) , 1)

は,4つのプロセスで各々計算したn!!!! , (n-1)!!!! , (n-2)!!!! , (n-3)!!!!をリストで与えます.

こうして並列化ができました.めっちゃ簡単ですね!

計算結果は

(シングルプロセス)Factorial 5012.873ms
(マルチプロセス)p_Factorial  276.728ms

やったね!∩(>◡<*)∩♡

参考:

http://gihyo.jp/dev/serial/01/pythonhacks/0005

http://docs.python.jp/3.3/library/multiprocessing.html

Haskell で Fizzbuzz

main :: IO()
main = do
	let
		fizzbuzz :: Int -> String
		fizzbuzz n	| n `mod` 15 == 0	 = "fizzbuzz"
				| n `mod` 3 == 0	 = "fizz"
				| n `mod` 5 == 0	 = "buzz"
				| otherwise			 = show n
	let
		fizzbuzz_lst :: Int -> [String]
		fizzbuzz_lst upper = [ fizzbuzz n | n

Fizzbuzz,こんなのを書きました.

Haskellではswitch構文の代わりに,数学の場合分けで使う { みたいなのをそのまま書きます.

otherwise なんかそのままですね.

fizzbuzz_lst は upper を引数にとる関数で,upperを上限にfizzbuzzを実行します.

逆に,こうしなければ 無限リスト(集合) をそのまま相手にすることができます.これもHaskellの特徴として随所に書かれていることですね.

個人的に,詰まったのは putStrLn と unlines だったりしますwww

putStrLn は文字列の最後に改行を入れて返します.

Prelude> putStrLn "ABCDE"
ABCDE

一方, putStr は改行を入れません.

Prelude> putStrLn "ABCDE"
ABCDEPrelude>

unlines は リストを改行挟んで返します.

Prelude> unlines ["1", "2", "3"]
"1\n2\n3\n"

Haskellを触ることは日常でも趣味でも殆どないんですが面白いな,と思います.