PageRank



轉移公告

計劃把 http://blog.hoamon.info/ 文章全部轉移至 http://www.hoamon.info/blog/ 這裡,而本 Blogger 站台的文章近 500 篇,我預計在 2014-12-31 前移轉完畢,完成後 http://blog.hoamon.info/ 將只作代轉服務,一律把舊連結如 http://blog.hoamon.info/index.html 轉成 http://www.hoamon.info/blog/index.html ,敬請舊雨新知互相走告。

新文章只發佈在 http://www.hoamon.info/blog/

何岳峰 敬上

2011年1月27日 星期四

近 250% 的報酬率,我前所未有的紀錄

這是繼 60% 的漲幅後,再一次突破我個人的紀錄。這一切要歸功於 HTC

當時外資紛紛看衰它,而我因為 HTC 幫 Google 代工自有品牌 Nexus One 手機這件事,對它非常有好感。也就在 330 元時,買了 80 股,而後又配了 4 股及幾千元的現金,成本也就降到 279 元。今天(2011-01-27)它股價收在 975 元,報酬率達 249% 。

千金難買早知道,如果當時我把手邊的錢全押在 HTC 上,總報酬率就是 249% ,而不是現在的 13% 。

然而我有這個屁股吃這種瀉藥嗎? 應該是沒有! 股票不會只漲不跌的。


如果手裡的股票只有宏達電,那它從 760 元下殺到 618 元時,我忍耐的住嗎? 就因為害怕所以在 730 元賣了 24 股。又或者能忍得住但我能睡得著嗎? 之前只擁有巨大時,就知道我的個性不是那種可以大而化之的人。

重壓宏達電勢必讓我沒有生活品質,而且這是我運氣好,如果重壓的是茂德,那故事就沒那麼有趣了。

有趣的是,因為現在擁有茂德、雷虎、台航…這些讓我賠錢的股票,反而我才睡得著覺。這就是被動投資呀!

2011年1月24日 星期一

使用 PayPal Express Checkout 作線上收款機制

若你不太了解什麼是金流系統,可以先去看「簡述金流系統」。

消費者在線上購買商品或勞務,所謂的付款其實只牽扯到兩件事:『身份驗證』及『確認額度』。但這兩件事都是特許公司如銀行或信用卡公司才能作的事。所以我們得透過中間人或中間人的中間人(金流公司)幫我們作到這兩件事,而我選的是 PayPal ,它是跨國的金流公司,我個人認為十分適合純網際網路公司使用。

從誰那裡匯多少錢到誰那裡? 有三個變數:『付款的人』、『付多少』及『收款人』。這『收款人』當然是我們自己的公司囉。在程式中設定收款帳戶只要設定『帳戶名稱(USERNAME)』、『密碼(PASSWORD)』及『簽名(SIGNATURE)」就行了,如何申請這三種資料請看我的另篇文章

而『付多少』的設定變數名則為 AMT 。但在消費者刷卡時,要讓他明確地了解買的東西到底有什麼? 價錢是多少? 要刷多少錢? 我們得另外設定訂單的顯示變數。有商品名稱(L_NAME0)、商品描述(L_DESC0)、商品編號(L_NUMBER0)、購買數量(L_QTY0)、商品單價(L_AMT0)、所有商品小計(ITEMAMT)、運送及處理費用(SHIPPINGAMT)、稅金(TAXAMT)等。

這些變數後有帶 0 的表示它可以是多值,如果該筆訂單有第二項商品的話,就設定 L_NAME1 、 L_DESC1 、 L_NUMBER1 、 L_QTY1 、 L_AMT1 ,以此類推。

這些訂單顯示變數有幾項原則:

  • ITEMAMT 必須等於 L_AMT0 * L_QTY0 + L_AMT1 * L_QTY1 + ... + L_AMTn * L_QTYn

  • AMT 必須等於 ITEMAMT + SHIPPINGAMT + TAXAMT


違反這兩個原則, PayPal 會報錯的。

而『付款的人』部份就不是我們程式設計師該處理的,這部份交由 PayPal 自己與消費者確認卡號是否正確、與發卡銀行確認是否允許消費者刷該筆訂單的金額。等到 PayPal 作完『身份確認』及『額度確認』後,PayPal 會回傳一個 TOKEN ,告知我們消費者有能力消費該筆訂單,如果我們接受該筆交易,就以這個 TOKEN 回覆給 PayPal ,那它就幫我們刷下消費者的卡片了。之後就能在 PayPal 的帳務管理介面中看到消費者的付款紀錄。

上面的觀念了解了,我們這就進行程式的實作吧!

PayPal 的付款程序要經過 3 次的 API 呼叫,分別是 SetExpressCheckout, GetExpressCheckoutDetails, DoExpressCheckoutPayment 。

  • SetExpressCheckout 是整理好一份訂單資訊供消費者瀏覽。

  • GetExpressCheckoutDetails 是抓取當次交易的詳細資訊,但不包含消費者的卡號。

  • DoExpressCheckoutPayment 要求 PayPal 對消費者進行刷卡動作,完成交易。


而消費者瀏覽網頁順序則是『我們的訂單頁面』=>『確定購買』=>『SetExpressCheckout』=>『PayPal 付款頁』=>『PayPal 確認頁』=>『GetExpressCheckoutDetails+DoExpressCheckoutPayment』=>『我們的購買成功頁面』。

我們自己所寫的『確定購買』程式中,會紀錄消費者的購買資訊,產生訂單編號,完成後執行 SetExpressCheckout API 呼叫動作。所謂的呼叫,其實不過就像是 html 中的 form submit 。很懶惰的作法是輸出一個如下的 html 表單,然後要求消費者自己手動按下送出鈕。


 1 <form method="POST" action="https://api-3t.paypal.com/nvp">
 2     <input type="hidden" name="USER" value="API_username_do_not_copy_me">
 3     <input type="hidden" name="PWD" value=" API_password_do_not_copy_me">
 4     <input type="hidden" name="SIGNATURE" value="API_signature_do_not_copy_me">
 5     <input type="hidden" name="L_NAME0" value="test_product_name">
 6     <input type="hidden" name="L_DESC0" value="test_description">
 7     <input type="hidden" name="L_NUMBER0" value="test1">
 8     <input type="hidden" name="L_QTY0" value="1">
 9     <input type="hidden" name="L_AMT0" value="85">
10     <input type="hidden" name="ITEMAMT" value="85">
11     <input type="hidden" name="SHIPPINGAMT" value="10">
12     <input type="hidden" name="TAXAMT" value="5">
13     <input type="hidden" name="AMT" value="100">
14     <input type="submit" name="METHOD" value="SetExpressCheckout">
15     <input type="hidden" name="VERSION" value="63.0">
16     <input type="hidden" name="CURRENCYCODE" value="TWD">
17     <input type="hidden" name="PAYMENTACTION" value="Sale">
18     <input type="hidden" name="CANCELURL" value="http://www.YourCancelURL.com">
19     <input type="hidden" name="RETURNURL" value="http://www.YourReturnURL.com">
20 </form>


這裡有幾個地方要注意, form method 一定是 POST , form action 一定是 https://api-3t.paypal.com/nvp ,input name="METHOD" 的 value 一定是 SetExpressCheckout 。

VERSION 代表你呼叫的 API 版本是多少,版本號太小的 API ,可能會有些參數不支援。不過,以我使用的經驗,上面的參數都能跑在 53 ~ 63 之間。但能設得愈大愈好。

而 CURRENCYCODE 代表收取的幣別, TWD 代表新台幣, USD 代表美金,其他貨幣請參閱這裡

PAYMENTACTION 的值有三種: Sale, Authorization, Order , Sale 表一般銷售,消費者要買,你一定賣; Authorization 表須確認的銷售,如消費者要買 Giant 的 TCR SL 3 車架,但貴公司沒建置庫存管理,所以消費者下單後,你得到大如足球場的倉庫去找,找得到就賣,找不到只好跟消費者 Say Sorry! Order 表須更長時間的確認銷售,像 Authorization 最多只會在帳務管理系統中等 3 天讓你按下請款鈕,但 Order 可以等到 29 天。

CANCELURL 是當消費者在 PayPal 付款頁中,反悔了,在他取消交易時, PayPal 會導引他回到你的網站。

RETURNURL 是當消費者在 PayPal 確認頁按下「立即付款」, PayPal 會導引他回到你的網站,理論上,這個網頁就是你執行 GetExpressCheckoutDetails + DoExpressCheckoutPayment 的地方。

從這個 html form 範例中,可以了解呼叫 SetExpressCheckout API 真的是非常簡單的事,只要把握正確的 name - value pair(nvp) 即可。

不過我們是 Python 程式設計師,怎麼能用 html form 這麼簡單的東西來呼叫 API ,當然要用 urllib 囉! 把下面的程式插到『確定購買』程式的最後面,這樣就不用消費者自己手動按送出鈕了。


 1 from google.appengine.api import urlfetch
 2 import urllib
 3
 4 string_hash = {
 5     "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
 6     "SIGNATURE": "API_signature_do_not_copy_me", "L_NAME0": "test_product_name",
 7     "L_DESC0": "test_description", "L_NUMBER0": "test1", "L_QTY0": "1",
 8     "L_AMT0": "85", "ITEMAMT": "85", "SHIPPINGAMT": "10", "TAXAMT": "5",
 9     "AMT": "100", "METHOD": "SetExpressCheckout", "VERSION": "63.0",
10     "CURRENCYCODE": "TWD", "PAYMENTACTION": "Sale",
11     "CANCELURL": "http://www.YourCancelURL.com",
12     "RETURNURL": "http://www.YourReturnURL.com",
13 }
14 form_data = urllib.urlencode(string_hash)
15 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
16     payload=form_data,
17     method=urlfetch.POST,
18     headers={'Content-Type': 'application/x-www-form-urlencoded'},
19     deadline=10)
20
21 hash = {}
22 for i in result.content.split('&'):
23     k, v = i.split('=')
24     hash[k] = urllib.unquote(v)
25
26 redirect_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=%s' % hash['TOKEN']
27 return HttpResponseRedirect(redirect_url)


跑到 redirect_url 網址後,就是 PayPal 自己與消費者互動的網頁,等到消費者確定付款了,就會再轉回我們的 RETURNURL 程式。在 RETURNURL 頁面中,首先呼叫 GetExpressCheckoutDetails 得到該 token 所對應的付款資訊。然後再執行 DoExpressCheckoutPayment 即可完成信用卡刷卡動作。


 1 # exec GetExpressCheckoutDetails
 2 token = request.GET.get('token')
 3 string_hash = {
 4     "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
 5     "SIGNATURE": "API_signature_do_not_copy_me", "METHOD": "GetExpressCheckoutDetails",
 6     "VERSION": "63.0", "TOKEN": token,
 7 }
 8 form_data = urllib.urlencode(string_hash)
 9 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
10     payload=form_data,
11     method=urlfetch.POST,
12     headers={'Content-Type': 'application/x-www-form-urlencoded'},
13     deadline=10)
14
15 hash = {}
16 for i in result.content.split('&'):
17     k, v = i.split('=')
18     hash[k] = urllib.unquote(v)
19
20 if hash['ACK'] != 'Success':
21     error_messages = []
22     for k, v in hash.items():
23         error_messages.append('%s: %s'%(k, v))
24     raise Exception(';\n'.join(error_messages))
25
26 # exec DoExpressCheckoutPayment
27 string_hash = {
28     "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
29     "SIGNATURE": "API_signature_do_not_copy_me", "METHOD": "DoExpressCheckoutPayment",
30     "VERSION": "63.0", "TOKEN": token,
31     "AMT": "100", "CURRENCYCODE": "TWD",
32 }
33 form_data = urllib.urlencode(string_hash)
34 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
35     payload=form_data,
36     method=urlfetch.POST,
37     headers={'Content-Type': 'application/x-www-form-urlencoded'},
38     deadline=10)
39
40 hash = {}
41 for i in result.content.split('&'):
42     k, v = i.split('=')
43     hash[k] = urllib.unquote(v)
44
45 if hash['ACK'] != 'Success':
46     error_messages = []
47     for k, v in hash.items():
48         error_messages.append('%s: %s'%(k, v))
49     raise Exception(';\n'.join(error_messages))
50
51 return HttpResponseRedirect('http://www.YourThankURL.com/')


就這樣,你會在 PayPal 的帳務管理系統中,看到消費者的付款紀錄。

簡述金流系統

網路改變了現代人很多的生活模式。論就原理,它不過是快速傳遞資訊而已,結果它可以把傳統語音訊號改成語音封包變成網路電話,而平面的郵購清單改成動態的網頁表單變成線上銷售,其實它的原理真的就只是能加快資訊傳輸的速度而已,但這「量變」卻造成「質變」。

金流也是。事實上,當各國央行放棄金本位制度後,所謂的貨幣就不過是個「數字」而已,美國聯準會可以搞 QE1, QE2, QE3 … 的原因,不是它美鈔可以印得比別人快,以 QE2 的規模 6000 億美元來看,美國印鈔局真有辦法在不到 1 年的時間印出 6000 億美元的鈔票嗎? 這還不算它本來就得應付的舊鈔換新鈔需求喔! 美鈔最大額不過是 100 元,印這個太慢了,所以它們印的是美國公債,隨便印都是 10 萬起跳的。當它們想要為金融體系注資時,就把當初發行的公債買回來就行了,而且還不用給現金,在資產負債表上掛帳就行了,可參閱聯準會買債券賺到784億美元

再以我們中央銀行為例,目前 3 千多億美金的外匯存底,真的是有實體資產放在央行的保險庫嗎? 當外資從紐約匯進 10 億美金,不過就是把某家銀行的美金數字換放到另一家銀行去就行了,根本不用搬真的錢進到台灣。所以金流根本就是資訊流,流通的資訊主要就是兩種,誰匯給誰以及匯多少。「誰匯給誰」關係『身份認證』這種事,而「匯多少」則部份與匯款人的額度也就是『身份認證』有關,剩下的部份就只是數字而已。

說起來金流還比通信網路簡單,至少它不需要使用者另外準備耳機及麥克風。以早期的資訊管理系統來說,會計系統通常是最早建置的,因為它們也只關乎數字。

金流系統聽起來這麼簡單,那我們會寫程式,會作資訊系統的人還不趕快來寫一套!

哈哈哈! 我就知道你不信我,金流系統如果怎麼簡單,怎麼沒聽說過那個大學沒畢業的有開發出來,到是有聽過沒畢業的人可以寫出社交網站; 但如果不簡單,怎麼天底下那麼多家銀行,幾乎每家都有金流系統,但也就那麼一個社交網站有著幾億人的使用者。

嘻! 這說法有沒有想到日近長安遠的故事。

原因不在程式難寫,而是『身份認證』太難。各位有聽過『軟體公司法』嗎? 乃規範軟體公司如何撰寫程式,收費標準以及沒事得接受政府檢查的法律,但是卻有銀行法及金管會,規範營業櫃台可放什麼,不可放什麼,能收取的利率上限為何,以及不定期與主管機關喝喝咖啡。

我們隨便寫個網站讓大家使用時,有沒有要使用者親自到公司櫃台辦理,而且還要帶雙證件及本人拍照喔! 沒有嘛! 因為銀行、信用卡公司都是特許行業,政府沒點頭,一般人是不能開的。你開公司時,在營業項目上面通常是高興拉多少就拉多少,開軟體公司能不能賣書? 可以! 能不能賣服飾? 可以! 但能不能寫個 H101021 商業銀行業? 我包你會被經辦人員白眼,嗆你一句:「請找個有正常腦袋的會計師幫你申請!」

於是乎,我們一般人寫金流系統,都需要找個代理人,幫我們作『身份認證』及『額度確認』的動作。那就是銀行提供的線上刷卡服務或是網路ATM系統,然而如果我們是跟玉山銀行(收單銀行)申請收款服務的,但消費者拿的是第一銀行(發卡銀行)的信用卡或是提款卡時,玉山銀行怎麼知道是真的卡還是假的? 它們得透過財金公司的金資系統作跨行查詢,信用卡則是透過信用卡組織像是 visamastercard 與發卡銀行查詢,在臺灣則用聯合信用卡中心作中介。

也因為金流系統真的只是數字交換而已,難作的『身份認證』及『額度開放』都被銀行、信用卡公司作完了,於是乎就有金流公司的誕生,它們整合 WebATM 匯款、信用卡刷卡甚至超商繳費,只要你跟它們簽約,每年繳個閘道服務費,就提供 API 使用。而我們程式設計師只要知道傳什麼參數給它就成了。因為簡單,所以就得付出代價,每筆交易的手續費大概是花 2.8 ~ 3.4 % 之間,比買股票還貴,平平都是數字,轉 100 元扣 3 塊,轉 1000000000 扣 3 億,這不過是多 7 個零而已。

撰寫金流系統前,需要考慮的是『用誰的 API 』,有國內銀行、金流公司及 PayPal 等。

國內銀行:

通常你的公司帳戶開在那家銀行,就跟它們合作,好處是有關係有優惠,如果公司進出金額又大時,手續費會比較容易砍,而且消費者刷卡、匯款後,錢是馬上匯到公司戶頭。缺點是國內銀行的 API 不好用,不要以為它們的資本額動輒幾百億上下,寫的網站就比較厲害,這不見得。它們的本業是賺存放款利差,不是開軟體公司。或許我一竿子打翻一船人,非常歡迎提出反證,畢竟我沒看過國內所有銀行的 API 文件。因為不容易看得到,這一點我也覺得很奇怪,銀行居然會把 API 文件當作是機密,一定要簽約後,才能看到全貌,憑這一點,我就不想用銀行的系統了。

金流公司:

好處是它們的軟體實力比較好, API 考慮比較周延,付款種類較多,入帳管理系統也比較好用,有意見的話也比較有改進的空間。而缺點是金流公司一大堆,不要找到二流的,二流的收款是先到金流公司戶頭,之後再轉到你的公司戶頭,出問題,錢是要不回來的。或是網路頻寬不夠,消費者要刷卡時,苦苦等不到刷卡頁面。甚至盜賣消費者資料。

不過,金管會對金流公司不太爽,法令綁手綁腳的。難保那天被勒令停辦,你就頭痛了。又或者一個解決方案是利用金流公司協助申請『特店資格』,有了特店資格,你就可合法地提供信用卡刷卡服務。

PayPal:

不須有公司登記,沒有建置費,可以跨國付款,軟體實力也是最高的,不只給個入帳管理系統,連帳務管理都有 API ,所以你高興還可以把帳務管理內建在自己的金流系統中,這樣你的會計就不用記兩組帳號、密碼,這邊登過來,那邊登過去了。缺點是它每筆交易收 3.4% + $10 TWD ,不算便宜。但是我們可以這樣想,公司不大時,用 PayPal 可以比較省成本,因為它少了上萬元的建置費,換算成 PayPal 手續費,大概可以抵上 1000 次,這對草創公司比較有利。另外還有一個不算缺點的缺點,它的 API 文件都是英文的,它沒有台灣辦公室,所以有程式問題要問,都得用英文問,像我就提了一個問題

以我個人偏好來說,在小規模時,採用 PayPal 收款,大規模時,納入一流金流公司,而銀行則完全不考慮。

這篇文章一開頭其實只是想講如何使用 PayPal Express Checkout 機制收款,結果落落長,到現在都還沒講到初衷,所以請看下篇來了解 Express Checkout 如何應用。

== 後記 ==

除了這三者收款管道外,我好像漏了聯合信用卡中心的特約商店。等我有時間再補充吧!

2011年1月23日 星期日

指派問題使用 python + lp_solve 解決

指派問題乃線性規劃的一種特例,它的特性是不須強調解為 0-1 變數或整數值,但最後算出來它卻一定就是 0 或 1 ,只是這種說法是學理上的,當我們使用程式來計算時,往往因為這些工具在計算過程中使用數值分析的方法,造成解的結果只會接近 0 或是 接近 1 ,而不是純正的 0 或 1。

這也就是我在第 73 行中,使用 v > 0 而不是 v == 1 的原因,如果是寫 v == 1 的話,有些 v 值是 0.999999 的,就不會顯現了。事實上,使用 v > 0.5 會更好。不過,我最後檢查時,發現 > 0 就可以秀出這 50 個 x 的值,也就算了。

lp_solve 函式庫安裝方法請見舊文


 1 # -*- coding: utf8 -*-
 2 """ 問題:
 3     
 4     指定 0, 1, 2, ..., 49 等 50 個不可重複的數字給 x0 ~ x49,例如 x0 = 12, x1 = 33, ...
 5
 6     y = sin(1*x0) + sin(2*x1) + sin(3*x2) + ... + sin(50*x49)
 7
 8     求解 y 之最大值?
 9
10     解法:
11
12     此問題可視為一種指派問題,也就是說有 0 ~ 49 等員工,要放到 x0 ~ x49 的職位去,
13     這樣決策變數就會變成 p00(值為 1 代表 x0=0), p01(值為 1 代表 x1=0),
14     p02 , ..., p49_49 等 2500 個決策變數,且其值必為 0 或 1 。
15
16     雖然目標函式看起來是非線性的,但其實是線性的, y 函式的係數應該長得如下:
17
18             x0          x1          x2          ...
19     0       0(C00)      0(C01)      0(C02)      ...
20     1       0.84(C10)   0.91(C11)   0.14(C12)   ...
21     2       0.91(C20)   -0.76(C21)  -0.28(C22)  ...
22     ...     ...         ...         ...         ...
23
24     所以如果決策變數是 p20 = p01 = p12 = 1,其餘為 0 ,則代表 x0 = 2,x1 = 0,x2 = 1,
25     這樣 y = 0.91 + 0 + 0.14 = 1.05 。
26
27     所以目標式可以寫成 y = C00 * p00 + C01 * p01 + ... + C49_49 * p49_49 。
28
29     最後再加上限制式
30     
31     p00 + p01 + ... + p0_49 = 1
32     p10 + p11 + ... + p1_49 = 1
33     ...
34     p49_0 + p49_1 + ... + p49_49 = 1
35
36     p00 + p10 + ... + p49_0 = 1
37     p01 + p11 + ... + p49_1 = 1
38     ...
39     p0_49 + p1_49 + ... + p49_49 = 1
40
41     等 100 條限制式後,就能求 y 的最佳解。
42
43 """
44 from math import sin
45 import lpsolve55 as L
46
47 LENGTH = 50
48 C = []
49
50 for i in xrange(LENGTH):
51     for j in xrange(LENGTH):
52         C.append(-1*sin((j+1)*i)) # lp_solve 預設解極小值問題,所以我把目標函數係數全乘以 -1
53
54 lp = L.lpsolve('make_lp', 0, LENGTH**2)
55 L.lpsolve('set_verbose', lp, L.IMPORTANT)
56 ret = L.lpsolve('set_obj_fn', lp, C)
57
58 for i in xrange(LENGTH):
59     p = [0,] * (LENGTH ** 2)
60     for j in xrange(i*LENGTH, i*LENGTH+LENGTH): p[j] = 1
61     ret = L.lpsolve('add_constraint', lp, p, L.EQ, 1)
62
63     p = [0,] * (LENGTH ** 2)
64     for j in xrange(0, LENGTH):
65         p[j*LENGTH+i] = 1
66     ret = L.lpsolve('add_constraint', lp, p, L.EQ, 1)
67
68 L.lpsolve('solve', lp)
69 print u'目標值: %s' % (L.lpsolve('get_objective', lp) * -1) #要乘以 -1 來還原目標值。
70 vars = L.lpsolve('get_variables', lp)[0]
71 print u'決策變數: %s' % vars
72 for (ij, v) in enumerate(vars):
73     if v > 0:
74         i = ij / LENGTH
75         j = ij % LENGTH
76         print 'x%s = %s, ' % (j, i),
77         if i % 5 + 1 == 5: print

目標值最佳解為 47.8620523191 。

各變數值如下:
x21 = 0, x32 = 1, x47 = 2, x33 = 3, x1 = 4,
x37 = 5, x16 = 6, x45 = 7, x11 = 8, x25 = 9,
x18 = 10, x30 = 11, x7 = 12, x17 = 13, x0 = 14,
x41 = 15, x36 = 16, x22 = 17, x49 = 18, x9 = 19,
x44 = 20, x26 = 21, x43 = 22, x13 = 23, x42 = 24,
x35 = 25, x8 = 26, x20 = 27, x39 = 28, x40 = 29,
x29 = 30, x10 = 31, x34 = 32, x4 = 33, x2 = 34,
x38 = 35, x24 = 36, x6 = 37, x46 = 38, x5 = 39,
x27 = 40, x28 = 41, x14 = 42, x23 = 43, x48 = 44,
x19 = 45, x31 = 46, x12 = 47, x15 = 48, x3 = 49,

=== 後記 ===

經老師指導後,使用

ret = L.lpsolve('set_binary', lp, [1,]*(LENGTH**2)) #大約加在第 59 行後

令決策變數為 0-1 二元變數後,計算時間馬上減少了 60% 。

道路施工的排程問題,類似背包問題,但須考慮不同的排列方式

如:長度 10 公尺的路面,若有 7 公尺/日、 5 公尺/日、 3 公尺/日的施工工班可供選擇,則有幾種的排程組合? 此問題很像背包問題,但在背包問題中,它不須考慮裝入物品的順序,而只考慮種類。若問題改為路面總長度 1000 公尺,而有 [260, 230, 190, 140, 80] 幾種工班時,我的解答是 69225 種。以下是我的解法:

 1 class LineSerial:
 2     u"""  目的:解路面排程問題,如:長度 10 公尺的路面,若有 7 公尺/日、 5 公尺/日、 3 公尺/日
 3         的施工工班可供選擇,則有幾種的排程組合。
 4
 5         解如下,共 17 種:
 6             [7, 7], [7, 5], [7, 3],
 7             [5, 7], [5, 5],
 8             [5, 3, 7], [5, 3, 5], [5, 3, 3],
 9             [3, 7],
10             [3, 5, 7], [3, 5, 5], [3, 5, 3],
11             [3, 3, 7], [3, 3, 5],
12             [3, 3, 3, 7], [3, 3, 3, 5], [3, 3, 3, 3],
13     """
14     def __init__(self, total, sizes):
15         """ serial_times 則是在計算 serial 函式被呼叫幾次。
16         """
17         sizes.sort(reverse=True)
18         self._sizes = sizes
19         self.serial_times = 0
20         self.result = []
21         self.serial(total, None, [])
22
23
24     def serial(self, total, length, tmp):
25         u""" 將 total 依序給 _sizes 中的所有元素去切,切完後就放入 tmp ,
26             當 total <= 0 時, 再放入 self.result 中。
27         """
28         #self.serial_times += 1
29         tmp.append(length)
30         if total <= 0:
31             self.result.append(tmp[1:])
32             return
33
34         for s in self._sizes: self.serial(total-s, s, tmp[:])
35
36
37
38 if __name__ == '__main__':
39     from time import time
40     total = 1000
41     lengths = [260, 230, 190, 140, 80]
42     time0 = time()
43     cs = LineSerial(total, lengths)
44     print time() - time0
45     print u'總組合數: %s' % len(cs.result)
46     print u'serial 遞迴次數: %s' % cs.serial_times
47     #for i in cs.result: print i

2011年1月22日 星期六

使用 genetic algorithm 來求解非線性問題。如 y = [ sin(1*x0) * sin(2*x1) ] + ... + [ sin(49*x48) * sin(50*x49) ],求 y 的最大值

問題描述: 指定 0,1,2,.........49 等50個數字給 x0~x49(不可重複),且

y = [ sin(1*x0) * sin(2*x1) ] + [ sin(3*x2) * sin(4*x3) ] + ... + [ sin(49*x48) * sin(50*x49) ]

請求解 y 之最大值?

本問題我使用 pyevolve 函式庫來幫我處理染色體的突變、重組、交配工作。我只需要提供目標函數(eval_func)的計算方式即可。本問題我的 y 最佳解是 20.4676 ,決策變數是 [33, 26, 36, 16, 45, 28, 37, 1, 19, 2, 25, 14, 0, 22, 6, 17, 35, 24, 11, 12, 27, 42, 49, 32, 13, 20, 23, 43, 41, 30, 4, 9, 21, 3, 10, 34, 38, 15, 18, 5, 47, 39, 44, 40, 8, 7, 31, 48, 46, 29] 。

 1 from pyevolve import G1DList
 2 from pyevolve import GSimpleGA
 3 from pyevolve import Selectors
 4 from pyevolve import Statistics
 5 from pyevolve import DBAdapters
 6 import pyevolve
 7 from math import sin
 8
 9 """ 指定 (0,1,2,.........49 等50個數字不可重複)給 x0~x49,例如  x0=12,  x1= 33, ....
10     y = [ sin(1*x0) * sin(2*x1) ] + [ sin(3*x2) * sin(4*x3) ] + ... + [ sin(49*x48) * sin(50*x49) ]
11     求解 y 之 最大值=?
12 """
13
14 def eval_func(chromosome):
15     score = 20.0 #為了不讓 score 的值小於 0,因為 pyevolve 不支援適存值小於 0 。
16     list = map(lambda a,b: (a, b), xrange(50), chromosome)
17     list.sort(key=lambda a: a[1])
18     for i in xrange(25):
19         score += sin((2*i+1)*list[i*2][0]) * sin((2*i+2)*list[i*2+1][0])
20
21     return score
22
23 # Enable the pyevolve logging system
24 pyevolve.logEnable()
25 # Genome instance, 1D List of 50 elements
26 genome = G1DList.G1DList(50)
27 # Sets the range max and min of the 1D List
28 genome.setParams(rangemin=0, rangemax=500)
29 # The evaluator function (evaluation function)
30 genome.evaluator.set(eval_func)
31 # Genetic Algorithm Instance
32 ga = GSimpleGA.GSimpleGA(genome)
33 # Set the Roulette Wheel selector method, the number of generations and
34 # the termination criteria
35 ga.selector.set(Selectors.GRouletteWheel)
36 ga.setGenerations(5000)
37 ga.terminationCriteria.set(GSimpleGA.ConvergenceCriteria)
38 # Sets the DB Adapter, the resetDB flag will make the Adapter recreate
39 # the database and erase all data every run, you should use this flag
40 # just in the first time, after the pyevolve.db was created, you can
41 # omit it.
42 sqlite_adapter = DBAdapters.DBSQLite(identify="ex1", resetDB=True)
43 ga.setDBAdapter(sqlite_adapter)
44 # Do the evolution, with stats dump
45 # frequency of 20 generations
46 ga.evolve(freq_stats=20)
47 # Best individual
48 print ga.bestIndividual()

使用 PayPal Express Checkout 時,如何申請 API 簽章?

要使用 PayPal 作為收款工具時,除了申請它的帳戶(建議是商業帳戶)外,若使用的是 Express Checkout 收款機制,你還需為自己所寫的程式申請一組 API 簽章,包含「用戶名稱」、「密碼」、「簽名」。

申請方式很簡單,先登入 www.paypal.com ,看到個人的總覽頁面如下圖:



點選「我的業務設定」。



點選「立即開始」。



點選「為 PayPal 帳戶要求 API 電子簽章」。



選擇「申請 API 電子簽章」,並點選「同意並提交」。



抄下「API用戶名稱」、「API密碼」、「簽名」放到你的程式碼中,就可以呼叫 PayPal 的 Express Checkout API 了。

2011年1月2日 星期日

算成績單該用「發行量加權股價報酬指數」來計算

2010年結束了,台股在這一年呈上漲格局。若以年初買股,而在年底賣股的情況下,很多媒體的計算方式是用加權指數來評估,得到 (8,972.50 - 8,207.85) / 8,207.85 = 9.31% 。這是錯誤的計算方式,它少算了領到的現金股利。

正確的計算方式應用「發行量加權股價報酬指數」來計算, (11,928.56 - 10,528.26 ) / 10,528.26 = 13.3% 。

也就是在 2010 年度沒有投入新資金的情況下,從 2009 年末抱股到 2010 年底的投資人,如果你的報酬率沒有 13.3% 的話,都是「不及格的」。詳細的評估介紹可看我的舊文

今年我的報酬率約有 11% ,看似不及格。但因為我 2010 年持續都有丟入資金(被動投資的其中一個原則就是分時買進,也分時賣出),直接算資產的總報酬率會低於真正的內部報酬率。所以我的實際成績單得從現金流量情形算出來。

理論上,是會更大的。應該有及格吧! 不過,沒及格也沒關係,因為我的持股比例並不照台股市值比例操作的,像台積電在台股市值約佔 8% 左右,但我的持股比例只有 3% 多,所以兩者不同步是應該的。

我真的不喜歡 Facebook

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

因為對它的隱私權政策並不滿意,再加上我對社群網站的喜好不高,所以我不玩 facebook.com 。話雖如此,我還是申請了一個帳號,因為我怕被別人佔用。

但申請了那個帳號,怎麼讓別人知道那個帳號的確是我的,而不是有其他相同姓名或是其他搗蛋鬼所創建的呢? 又或者 是被 facebook.com 的工程師,纂改了那個帳號的信箱,假裝那是「何岳峰」的帳號呢?

最簡單的方法就是使用 PGP 來證明那是我(何岳峰 hoamon@hoamon.info)所開設的 fb 帳號( http://www.facebook.com/profile.php?id=1633143675 )。只要在我發表的文章內,加上 fb 的 account id 及 login account ,並整個用 244E7AEB 的私錀作簽章。那所發表的文章就的的確確可以證明是擁有 244E7AEB 私錀的人所發表的,而我又把 244E7AEB 的公錀資訊放在我的名片上,並發放給其他有見過面的朋友。這樣我的朋友用我的公錀就能驗證這篇文章。

PS http://www.facebook.com/profile.php?id=1633143675 這個塗鴉牆上的文章不能被我的公錀驗證,乃是因為 fb 網站破壞了該簽章文的純文字內容。但還好各位可點進名片檔的那張圖檔中,從那邊驗證。
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Use GnuPG with Firefox : http://getfiregpg.org (Version: 0.8)

iEYEARECAAYFAk0fVZAACgkQmNBN3SROeutO2QCggkqlp9Jv+J27bJKEgJVBusMx
CZkAoNL+PUfXri+1SUnlEoV1VoKUnHjp
=4HXa
-----END PGP SIGNATURE-----

BTW 我的 fb 帳號,及我的其他 PGP 文章

== 後記 ==

來到這裡的朋友們,你們怎麼知道這裡的facebook帳戶( www.facebook.com/amon.ho )真的是「何岳峰」所開設的,我放了相片,也寫一些個人資訊,但難到不會是騙人的嗎?從相片及個人資訊就可真的確認是同一人嗎?試想一個狀況,一個「何岳峰」的朋友,他可以拿到「何岳峰」的相片,也知道「何岳峰」從小到大的教育歷程及工作經歷。那他可不可以開設「何岳峰」的facebook呢? 現在的facebook又不驗證身份證號。你會想,這世界不會有人這麼無聊吧! 事實上就是有,而且他的目的,就是搞社交工程。所以為了證明,這個帳號的確是唸「四育國中、台中二中、中興大學土木系」的何岳峰所擁有。我用私錀來簽章本段文句
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.10 (GNU/Linux)

owFlU01PE1EUHVCMkJhITIw7q3GhG/wHsjAxRoMrNya6AKIxGqg7jKtpQZgyLdNK
KdROKF+FIpZWRmGc0urCxIXGmGjUjYmRd9+biTEu3ZjgeR1oCGwm792595xzz70v
fmif0tg68bHj+6krD341vPO6lI5P73+z6iBpJU9Nu7PT4vEAN3UydFITf9ajrDKF
A1dHPGddZHNeaLSedquz+2ZXMHiXbItrq6cDfX19bduxtu5gz9nOnmBv2+1g4Iww
sxJ2orihAnCMViyyShtqjEdUL6W7+QL+gotrCZ6sMmdQZGwRGZLsL7NUXGK2ypwM
qTpzHNcacvPDNWGDXmYWspkd42Y/wL18GgmAovGRdqpO+ihkDO+spNIzMoq+IDHj
uE9iqKR4tMbhyEp3cZ73W7ijTOgqt0KSrXbdJb9ulUwop4DLyjmuv4KovZk7e/KN
3JUDxVQyUEtzCxJ5LO2GV3hhTeR12cNajlVMsTqKyIYa9sKzW4x2zOf1jdzLW59S
YqY9IIwqmfkd0ddBMjRgeIvjbiHiOkusXJGHdBYkmL10tt+Cakyd2SkxFt2y24zA
LgTlWgxMu6Fhii+cCDBHp+I8s6XN8BVZKHWhyU5Cbs2FZX/WWwnxSTGHic+hPfQJ
TqwEmhFhB2sAIXxixCeH+9gz6PLnJoeWtNEtZTKwiUyd2Wg+RAb2ocCcqH/F19U0
GEoFm8wsR+9W2felbhMY+WgIUiW7lhDJvFgIeVEVj0KUKmIJHjzlyy94CquUa9Eu
7FdaG5UDTY3y4SgtzYe3X9OHf8rkuYZv14+me+7/vXrp4Ge68fPLZtMRZerrjzuX
r232Hn947+SjN8fOP6e3zRf/Aw==
=zwEg
-----END PGP MESSAGE-----
因應帳號ID改成專屬網址 www.facebook.com/amon.ho 所作的新簽章。
Related Posts Plugin for WordPress, Blogger...