andelf fledna Feather

2010年4月21日星期三

其实 IronPython 不是那么靠谱

原因大概是 .Net/C# 东西太多了... 很多特性在 py 下就不一定有那么优雅的实现
比如 clrtype 模块....
比如 Interface.

如果有一天 .NET/IronPython 有 JVM/Clojure 那么靠谱就好了.
Clojure-Clr 貌似也不靠谱..�

2010年4月17日星期六

[IronPython]WPF应用的 STAThread 属性处理

最近用铁蟒写 WPF 应用, 遇到纠结的问题. (使用 tools/pyc.py 编译时会遇到, 解释执行正常) 任何一个 WPF 程序,Main 的前面都必须有 [STAThread] 属性, 否则会有运行时错误: Unhandled Exception: System.InvalidOperationException: The calling thread must be STA, because many UI components require this. 找了下相关资料 发现有 http://www.ironpython.info/index.php/Setting_the_Clipboard 整了个还算 Pythonic 的方法, 这里和大家分享下 from System.Threading import Thread, ParameterizedThreadStart, \ ApartmentState, ThreadStart def STAThread(main): def new_main(*args, **kwargs): t = Thread(ParameterizedThreadStart(main)) t.ApartmentState = ApartmentState.STA t.Start(*args, **kwargs) return new_main 这样, 可以直接使用 @STAThread 修饰主函数. 由于使用了 ParameterizedThreadStart, 主函数必须接受参数. 然后想到了版本2 def STAThread(main): if main.__code__.co_argcount: # if main accept params def new_main(*args, **kwargs): t = Thread(ParameterizedThreadStart(main)) t.ApartmentState = ApartmentState.STA t.Start(*args, **kwargs) else: def new_main(): t = Thread(ThreadStart(main)) t.ApartmentState = ApartmentState.STA t.Start() return new_main 需要注意的是, 如果主函数写在 class 里,那么 @STAThread 必须在 @staticmethod 之后, 原因..(如果你知道 @ 是什么意思的话). 或许有其他更好的方法, 欢迎讨论 :)

2010年4月14日星期三

信息学院学生信息 Dump

# -*- coding: utf-8 -*-
#  FileName    : isejob.py 
#  Author      : Feather.et.ELF <andelf@gmail.com
#  Created     : Wed Apr 14 16:07:39 2010 by Feather.et.ELF 
#  Copyright   : Feather Workshop (c) 2010 
#  Description : www.isejob.neu.du.cn user info dump 
#  Time-stamp: <2010-04-14 17:55:19 andelf> 

import urllib, urllib2, re
from Tkinter import *
# this is a comment

login_url = "http://www.xxxxx.edu.cn/loginp.aspx" # note 'p' here
post_data = "userName=%s&userPass=%s"

urllib2.install_opener( urllib2.build_opener( urllib2.HTTPCookieProcessor() ) )

def trans_line(l):
    # l = l.replace("</tr>", "\n</tr>")
    keys = re.findall(r"<b>(.+?)<", l, re.UNICODE) # 50
    vals = re.findall(r"<td>(.*?)<", l, re.UNICODE) # 49
    # 最后一项为备注: <td colspan="3"></td>
    val_last = l.split('colspan="3">')[1].split("<")[0]
    vals.append(val_last)
    return dict(zip(keys, vals))
def login(no):
    # pre
    urllib2.urlopen("http://www.isejob.neu.edu.cn/login.aspx")
    no = int(no)
    req = urllib2.Request(login_url,
                          post_data % (str(no), str(no)),
                          {"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)",
                           "Referer": "http://www.isejob.neu.edu.cn/login.aspx"}
                          )
    res = urllib2.urlopen(req)
    return u"登录成功" in unicode(res.read(), 'utf-8')

def get_info(no=None):
    req = urllib2.Request(info_url)
    res = urllib2.urlopen(req)
    for line in res:
        line = unicode(line, 'utf-8')
        if u"用户类型" in line:
            return trans_line(line)
    return {}

def logout():
    return u"对不起" in unicode(urllib2.urlopen(logout_url).read(), 'utf-8')

def show_biref(info_dict):
    return unicode("%(姓名)s %(性别)s %(生源地)s %(家庭详细地址)s 手机:%(手机号码)s QQ:%(QQ号码)s 寝室:%(寝室号)s", 'utf-8') % info_dict

def show_detail(info_dict):
    lines = []
    for k in info_dict:
        if info_dict[k]:
            lines.append( u"%s: %s" % (k, info_dict[k]))
    return u'\n'.join(lines)

def test():
    for no in xrange(0, 0):
        if login(no):
            info = get_info()
            show_biref(info)
            logout()

class Application(Frame):
    def query(self):
        print self.inputs.get()
        no = self.inputs.get()
        if logout() and login(no):
            data = show_detail(get_info())
            #data = show_biref(get_info())
            self.infoLabel['text'] = data
        else:
            self.infoLabel['text'] = "Error"
    def initWidgets(self):
        ety = self.inputEntry = Entry(self)
        ety.pack(side='top')
        self.inputs = IntVar()
        self.inputs.set(20073033)
        ety['textvariable'] = self.inputs
        ety.bind('<Key-Return>', self.query)
                                  
        btn = self.queryButton = Button(self)
        btn["text"] = u"查询"
        btn["fg"] = "red"
        btn["command"] = self.query
        btn.pack(side="top")

        lbl = self.infoLabel = Label(self)
        lbl.pack(side="top", expand=1)
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        self.initWidgets()
def basic_ui():
    root = Tk()
    root.title(u"信息学院查询器")
    app = Application(root)
    app.pack()
    root.mainloop()
    
if __name__== '__main__':
    basic_ui()
## 是否定向 单位联系人 家庭详细地址 用户类型 学生干部任职 是否贷款 父亲 常用E-mail地址 母亲 政治面貌 家庭邮编 性别
## 所属组 录取研究生情况 班级 用户名 单位名称 意向城市 外语语种 所在年级 单位联系电话 挂科情况 未找到 QQ号码 手机号码
## 综合排名 民族 单位性质 不想找 就业状态 姓名 六级分数 学号 单位详细地址 家庭电话 计算机等级 生源地 出生年月日 四级分数
## 寝室电话 定向单位名称 专业 意向单位 寝室号 入学年级 应聘方式 单位传真 单位邮编 备注 意向行业
            

2009年7月31日星期五

这是逻辑? Three Idols

好玩的题, 题目是这样的:

这里我们有三个 God, A, B, C. 对应着 True-God, False-God, Random-God, 当然, 你不知道具体对应关系如何. True-God 的回答总是正确的, False-God 的回答总是错误的, 而 Random-God 的回答是随机的. God 使用单词 ja, da 代表 Yes 和 No, 当然, 你也不知道具体哪个是 Yes, 哪个是 No. 你有三次机会, 每次只能问其中一个 God 问题, 问如何判断 A B C 的对应关系. 

在看了提示后想到如下解决方法:

题目对于 Random-God 的行为表述不是很清楚, 比如回答前是否需要知道答案. 这里我们假设 Random-God 在确立随机性前需要知道答案是什么.

我们使用一道邪恶的题目, "你对本题的回答是永远一样的么?", 这样 False-God 和 Random-God 遇到这题就傻B了, 而 True-God 的答案(无论是 ja, da) 对应着 Yes.

然而, 虽然这个问题很邪恶, 但是无法判断连着两次提问遇到傻 B 的情况. 判断树深度大于 3, so, 解决方法不行.

继续看提示, 发现可以这么问, 比如问 A, "如果我问'B 是 Random-God 么?', 你会回答 `ja` 对么?", 这么一来, 如果回答的是 `ja`, 那么要么 A 是 Random-God, 给出了随机答案; 要么 B 是 Random-God(这两种情况下, C 都不会是 Random-God).  如果回答的是 `da`, 则要么 A 是 Random-God; 要么 B 不是 Random-God(这两种情况下, B都不会是 Random-God).

这样一来, 我们起码知道了一个不是 Random-God, 假设它为 C, 问它 "如果我问'你是 True-God 么?', 你会回答 `ja` 对么?", 那么他回答 `ja` 就代表它是..... 如果他回答 `da` 就代表它是......

继续问这个 C, "如果我问'B 是 Random-God 么?', 你会回答 `ja` 对么?",..... Orz....

很绕啊~~~

"如果我问'你明白了么?', 你会回答 `ja` 对么?"

2009年7月29日星期三

解决 End of file during parsing: .emacs

其实...是括号不匹配. 解决方法 M-x check-parens 找到不匹配的括号.

2009年7月15日星期三

Compile haskell package on win32

Many haskell packages depends on some libs, for e.g. libssl, libcurl, ... so, when that goes to win32, things become complicated... I find an easy way to do it: Install Dev-cpp and use its devpackage system. There are lots of packages for c/c++, so when compile haskell packages: simply pass --extra-include-dirs= and --extra-lib-dirs= to Setup.[l]hs

2009年7月14日星期二

质数/素数 Haskell 求解

在 ProjectEuler 经常遇到质数求解的问题, 需要一个够强大的算法. 尝试自己写了个, 用了 Memoization:
primeList :: [Integer]
primeList
= 2:3:5:[p | p <- [7,9..]
      , all ((0 /=) . mod p) $ takeWhile (<= ceiling $ sqrt $ fromInteger p) primeList ]
在 Hugs 下测试:
Main> primeList !! 1000
7927 :: Integer
(3341273 reductions, 4756123 cells, 5 garbage collections)
貌似不错, 但是很明显, 代码适用范围有限, 例如 primeList !! 10000 在半天后终于出结果. ssword 提供了一个更短的算法, 目测貌似没我的效率高:
primes :: [Integer]
primes = sieve [2..]
    where sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p > 0]
代码相当巧妙, 很不错的筛选法, 但是效率实测... 估计是时间花在 [] 上和不断的回朔上, Lazy 嘛~ 发现用到下个值只好回朔到 2, 3, 5, 7, 11, 13....
Main> primes !! 1000
7927 :: Integer
(35111063 reductions, 51142767 cells, 59 garbage collections)
以上算法都只是处理小质数数列, 遇到大质数.... 全部死掉. PS, stack overflow. 熟悉的错误. 我找到了这个 http://en.wikipedia.org/wiki/Miller-Rabin_test, 感觉不错, 下面的 Haskell 算法是自己写的, 很丑陋.... 根据 Python 代码改的. Miller Rabin 筛选法.
-- Miller-Rabin methold By Andelf
-- true for p < 10^16 except `46 856 248 255 981’, so you can add 13
-- optimize: order of and, or, any, all/ all judge to odd/even
isPrime :: Integer -> Bool
isPrime p
    | p == 2          = True 
    | even p || p < 2 = False
    | otherwise    
        = all (isPrimeTest p) (takeWhile (< p) [2, 3, 7, 61, 24251])
    where 
      isPrimeTest :: Integer -> Integer -> Bool   
      isPrimeTest n a 
          = odd d || t == n - 1 
          where 
            (t, d) = loop (pow a (n-1) n) (shiftTillOdd (n - 1))
            loop t d = if t /= 1 && d /= n - 1 && t /= n - 1 
                       then loop (t * t `mod` n) (d + d) 
                       else (t, d)
            shiftTillOdd = until odd $ flip div 2
            pow :: Integer -> Integer -> Integer -> Integer 
            pow a d n
                | even d            = pow (a * a `mod` n) (d `div` 2) n `mod` n 
                | d == 1 || a == 1  = a
                | otherwise         = pow (a * a `mod` n) (d `div` 2) n * a `mod` n
本来想用 AKS 的, 后来发现在多项式判断那块时间太长, 所以还是采用了伪素数算法, 你所看到的第 2 行注释, p < 10^16 except `46 856 248 255 981’ 是没问题的. 代码经过简单优化, guard 判断的分支顺序可能很诡异, mod, even, odd, 等函数的使用可能也很诡异, 但请相信这个是在 Hugs 下测试过的, 目前是最优. div/(+) 就是比 Data.Bits 快很多. 很诡异. ghc 同学请自己权衡. 再次动手可能在 pow 函数上. [2, 3, 7, 61, 24251] 的选择请参考链接.
Main> head $ filter isPrime [10 ^ 100..]
100000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000267 :: Integer
(8965148 reductions, 25399307 cells, 29 garbage collections)
参考链接 不是最优, 仅供参考.