勇闖新世界︰ 《 pyDatalog 》【專題】之物件導向設計‧一

人們對『思』、『學』、『習』三個字的『難易煩』通常不甚了了 。『思所學』之『難』因『所識所知』不足而『實難』。『習所學 』當時雖『易』,然而『煩』練習之『多』,所以『難』久持也。故而『學』或僅祇在『整理』『思』『習』之事乎?卻早為『煩』『難』所苦,未可竟其『功』,因此『積累難清』豈能不『錯讀』天下書的呢!這也就是

音樂播放器之 CD 轉成 mp3《三》下‧上》一文 ───

在進入『  PiTFT 3.5″ 觸控螢幕』之前,讓我們先補充一下,如何在樹莓派上,用命令列來播放 CD ︰

mplayer cdda:// 【default /dev/cdrom】
mplayer -cdrom-device /dev/sr0 cdda://

。俗話說︰書到用時方恨少。其實這是實務上常有的狀況,近年來更由於科技飛速變遷倍增壓力。如果真的有『藤子.F.不二雄』所說的《 小叮噹的記憶土司!!》果然幫的上忙嗎?縱使『學海無涯』只是顯現《如何閱讀□○??》的重要性。假使一個人能夠『固守』所學之『』,將它『連接』成『』,『編織』為『』,『貫串』一『』,就算『學網恢恢』也該是『疏而不漏』的吧!!

當我們『閱讀』他人的『文章』,也許會發現『胡適之』先生的『讀書四到』之好處,於此引用他講的『手到』︰

手到的功用。我常說:發表是吸收智識和思想的絕妙方法吸收進來的智識思想,無論是看書來的,或是聽講來的,都只是模糊零碎,都算不得我們自己的東西。自己必須做一番手腳,或做提要,或做說明,或做討論,自己重新組織過,申敘過,用自己的語言記述過,–那種智識思想方才可算是你自己的了。

。如果將此用於『樹莓派』的『學習』上,就是親身『動手做』 Do It Yourself ,如是漸次建立了自己的『思想』與『作法』。當『聽聞』各種『議論』── 比方說udevadm freezes board》── 時,我們可以『驗證』與『判斷』【 udevadm info -a -n /dev/sda 】是否會發生那篇文章所說的事?假使真的會,那麼這個『音樂播放器』上的『程式設計』就必須小心的避開那個可能引發『當機』的 Bug。其實那篇論壇上的癹文 Post 所說之事,曾經發生過 ── 見《Oops in dwc_otg_dump_spram running udevadm #21》── ,就作者當時所『』之記憶︰只要在『 udevadm 』指令上使用『 – -attribute-walk 』選項,就會當機,與使用的 kernel 版本有關。之後『樹莓派基金會』為了能更好的服務『使用者』,於是決定發行『官方版』,此時就與『 raspbian.org 』的發行分開了。或許正因那癹文者不知道過去的一段歷史所導致的吧!

───

所說之事者耶??!!

如是當『邏輯編程』遇到『物件導向』,這兩種『方法學』是否會發生競奪?還是能『相輔相成』或『相反相成』的呢?作者並沒有深入探究此事,也只能用

《韓非子》 ‧《難一

歷山之農者侵畔,舜往耕焉,期年,甽畝正。河濱之漁者爭坻,舜往漁焉,期年,而讓長。東夷之陶者器苦窳,舜往陶焉,期年而器牢。仲尼歎曰:「耕、漁與陶,非舜官也,而舜往為之者,所以救敗也。舜其信仁乎!乃躬藉處苦而民從之,故曰:聖人之德化乎! 」

或問儒者曰:「方此時也,堯安在?」其人曰:「堯為天子。」「然則仲尼之聖堯奈何?聖人明察在上位,將使天下無姦也。今耕漁不爭,陶器不窳,舜又何德而化?舜之救敗也,則是堯有失也;賢舜則去堯之明察,聖堯則去舜之德化;不可兩得也。楚人有鬻楯與矛者,譽之曰:『吾楯之堅,莫能陷也。』又譽其矛曰:『吾矛之利,於物無不陷也。』或曰:『以子之矛陷子之楯,何如?』其人弗能應也。夫不可陷之楯與無不陷之矛,不可同世而立 。今堯、舜之不可兩譽,矛楯之說也。且舜救敗,期年已一過,三年已三過,舜有盡,壽有盡,天下過無已者,以有盡逐無已,所止者寡矣。賞罰使天下必行之,令曰:『中程者賞,弗中程者誅。』令朝至暮變,暮至朝變,十日而海內畢矣,奚待期年?舜猶不以此說堯令從己,乃躬親,不亦無術乎?且夫以身為苦而後化民者,堯 、舜之所難也;處勢而驕下者,庸主之所易也。將治天下,釋庸主之所易,道堯、舜之所難,未可與為政也。」

管仲有病,桓公往問之,曰:「仲父病,不幸卒於大命,將奚以告寡人?」管仲曰:「微君言,臣故將謁之。願君去豎刁,除易牙,遠衛公子開方。易牙為君主味,君惟人肉未嘗,易牙烝其子首而進之;夫人情莫不愛其子,今弗愛其子,安能愛君?君妒而好內,豎刁自宮以治內,人情莫不愛其身,身且不愛,安能愛君?聞開方事君十五年,齊、衛之間不容數日行,棄其母久宦不歸,其母不愛,安能愛君?臣聞之:『矜偽不長,蓋虛不久。』願君去此三子者也 。」管仲卒死,桓公弗行,及桓公死,蟲出尸不葬。

或曰:管仲所以見告桓公者,非有度者之言也。所以去豎刁、易牙者,以不愛其身,適君之欲也。曰「不愛其身,安能愛君」,然則臣有盡死力以為其主者,管仲將弗用也。曰「不愛其死力,安能愛君」,是君去忠臣也。且以不愛其身,度其不愛其君,是將以管仲之不能死公子糾度其不死桓公也,是管仲亦在所去之域矣。明主之道不然,設民所欲以求其功,故為爵祿以勸之;設民所惡以禁其姦 ,故為刑罰以威之。慶賞信而刑罰必,故君舉功於臣,而姦不用於上,雖有豎刁,其奈君何?且臣盡死力以與君市,君垂爵祿以與臣市,君臣之際,非父子之親也,計數之所出也。君有道,則臣盡力而姦不生;無道,則臣上塞主明而下成私。管仲非明此度數於桓公也,使去豎刁,一豎刁又至,非絕姦之道也。且桓公所以身死蟲流出尸不葬者,是臣重也;臣重之實,擅主也。有擅主之臣,則君令不下究,臣情不上通,一人之力能隔君臣之間,使善敗不聞,禍福不通,故有不葬之患也。明主之道,一人不兼官,一官不兼事。卑賤不待尊貴而進,論,大臣不因左右而見。百官修通,群臣輻湊。有賞者君見其功,有罰者君知其罪。見知不悖於前,賞罰不弊於後 ,安有不葬之患?管仲非明此言於桓公也,使去三子,故曰管仲無度矣。

………

『故』事『過』的了!?

 

 

 

 

 

 

 

勇闖新世界︰ 《 pyDatalog 》【小品】之八皇后問題

什麼是『知識』?長久以來,西方的主流思潮中有一個稱之為『JTB』 justified true belief  的『經確證的真信念』之理論,它是這麼定義『知識』與『知道』的︰

The JTB account of knowledge is the claim that knowledge can be conceptually analyzed as justified true belief — which is to say that the meaning of sentences such as “Smith knows that it rained today” can be given with the following set of necessary and sufficient conditions:

A subject S knows that a proposition P is true if and only if:

P is true, and
S believes that P is true, and
S is justified in believing that P is true

JTB 理論對於知識的解釋是︰宣稱知識可以概念解析為經確證的真信念 ── 這就是說『史密斯知道今天下雨』一句話的意義,可以用如下之充份與必要的條件來給定︰

 

 

一位主體 S 知道一個命題 P 是真的,若且唯若︰

一、 P 是真的,且
二、S 相信 P 是真的,而且
三、S 有經確證的真信念相信P 是真的

在 這個定義下『知道□』意味著有『□的知識』,因為『知識』是由『真的命題』構成,所以必須有第一條件;如果某甲 『聽說』過 □ ,但是不相信,或者以為它是『假的』,當然不能說他知道□;再者雖說某甲相信□,卻出於無『理據』,比方說從『不知哪裡』得來的,一但『爭論』將無法『辯 護其說』,所以也不能講他真知道□。如此說來,這個定義該是很完善的了,但是卻受到美國哲學家 Edmund Gettier 的反駁,他說即使上述的三條要件都得到了滿足,有些情況下我們仍然不能聲稱『某甲知道□』── 這就是知名的『葛梯爾問題』 ──。如今葛梯爾問題之多都成『問題集』了,於此就說一個經典的『空地上的奶牛』 The Cow in the field 問題︰

一 位農民正擔心自己獲獎的奶牛走失了;這時送奶工到了農場,告訴他說︰不必擔心,他看到那頭奶牛在附近的一塊空地上。雖然農民很相信送奶工,但是他還是親自 的望了望,見著了熟悉的黑白相間之物,感覺滿意的放下心來。隔了一會兒,送奶工走過那塊空地想再次確認,他發現那頭奶牛確實是在那裡,不過現在它躲進樹林 裡了,並且空地上還有著一大張黑白相間的紙纏在樹上。顯然是,農民把這張紙錯認成那頭奶牛的了;於是問題就來了,雖然奶牛一直都在空地上,假使農民說自己 知道奶牛在空地上時,此時這句話是正確的嗎?……

─── 摘自《基因改寫 ── Thue 改寫系統之補充《二》

 

若說『相信』產生『信念』,『信念』的強度,將『可信』之『反例』給『排除』後得到加強。『懷疑』卻因『不可信』之『反例 』『排除』不了而引發。如是看來,處於『真』和『假』兩極之間的『信念』與『懷疑』往往在一者過強之時,向另一者方向變化 ,恐由於『事例眾』,『反例』就『多』之故。科學探究大自然的『知識』,也可以說是『真』和『假』的『過濾器』,『排除』假的,保留『真』的,那麼在『科學』發達的今日,是否也意味著『懷疑』之心也加強了呢?人類想知道『宇宙有沒有』其它像人類一樣高等生命之情又來自哪裡??現今能用的辦法,究其實果真可『確定』的講︰我們知道我們並不孤單,還有生命在時空的涯角呢 !!

就讓我們借著一八四八年,馬克斯‧貝瑟爾 Max Bezzel ,一位國際西洋棋棋手,提出的『八皇后問題

八皇后問題是一個以西洋棋為背景的問題:如何能夠在 8×8 的西洋棋棋盤上放置八個皇后,使得任何一個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。

追朔了解一下 pyDatalog 範例中所用的方法,查核一下我們能否講︰我們知道 pyDatalog 這個語言的用法。

關於八皇后問題的解法,維基百科已作了很好的總結︰

Eight queens puzzle

Finding all solutions to the eight queens puzzle is a good example of a simple but nontrivial problem. For this reason, it is often used as an example problem for various programming techniques, including nontraditional approaches such as constraint programming, logic programming or genetic algorithms. Most often, it is used as an example of a problem that can be solved with a recursive algorithm, by phrasing the n queens problem inductively in terms of adding a single queen to any solution to the problem of placing n−1 queens on an n-by-n chessboard. The induction bottoms out with the solution to the ‘problem’ of placing 0 queens on the chessboard, which is the empty chessboard.

This technique is much more efficient than the naïve brute-force search algorithm, which considers all 648 = 248 = 281,474,976,710,656 possible blind placements of eight queens, and then filters these to remove all placements that place two queens either on the same square (leaving only 64!/56! = 178,462,987,637,760 possible placements) or in mutually attacking positions. This very poor algorithm will, among other things, produce the same results over and over again in all the different permutations of the assignments of the eight queens, as well as repeating the same computations over and over again for the different sub-sets of each solution. A better brute-force algorithm places a single queen on each row, leading to only 88 = 224 = 16,777,216 blind placements.

It is possible to do much better than this. One algorithm solves the eight rooks puzzle by generating the permutations of the numbers 1 through 8 (of which there are 8! = 40,320), and uses the elements of each permutation as indices to place a queen on each row. Then it rejects those boards with diagonal attacking positions. The backtracking depth-first search program, a slight improvement on the permutation method, constructs the search tree by considering one row of the board at a time, eliminating most nonsolution board positions at a very early stage in their construction. Because it rejects rook and diagonal attacks even on incomplete boards, it examines only 15,720 possible queen placements. A further improvement, which examines only 5,508 possible queen placements, is to combine the permutation based method with the early pruning method: the permutations are generated depth-first, and the search space is pruned if the partial permutation produces a diagonal attack. Constraint programming can also be very effective on this problem.

An alternative to exhaustive search is an ‘iterative repair’ algorithm, which typically starts with all queens on the board, for example with one queen per column.[8] It then counts the number of conflicts (attacks), and uses a heuristic to determine how to improve the placement of the queens. The ‘minimum-conflicts’ heuristic — moving the piece with the largest number of conflicts to the square in the same column where the number of conflicts is smallest — is particularly effective: it finds a solution to the 1,000,000 queen problem in less than 50 steps on average. This assumes that the initial configuration is ‘reasonably good’ — if a million queens all start in the same row, it will obviously take at least 999,999 steps to fix it. A ‘reasonably good’ starting point can for instance be found by putting each queen in its own row and column so that it conflicts with the smallest number of queens already on the board.

Note that ‘iterative repair’, unlike the ‘backtracking’ search outlined above, does not guarantee a solution: like all hillclimbing (i.e., greedy) procedures, it may get stuck on a local optimum (in which case the algorithm may be restarted with a different initial configuration). On the other hand, it can solve problem sizes that are several orders of magnitude beyond the scope of a depth-first search.

Eight-queens-animation.gif

This animation illustrates backtracking to solve the problem. A queen is placed in a column that is known not to cause conflict. If a column is not found the program returns to the last good state and then tries a different column.

 

有興趣 N 皇后問題的多種 Python 程式解法者,可以參考

http://rosettacode.org/wiki/N-Queens#Python 》這個網頁。

 

此處特舉 Raymond Hettinger 先生於二零零九年二月十號所發表的

Eight queens. Six lines. (Python recipe)》處方︰

What six lines of Python can do

from itertools import permutations

n = 8
cols = range(n)
for vec in permutations(cols):
    if (n == len(set(vec[i]+i for i in cols))
          == len(set(vec[i]-i for i in cols))):
        print vec

 

Solver for the eight queens puzzle:
http://en.wikipedia.org/wiki/Eight_queens_puzzle

Computes all 92 solutions for eight queens. By setting n to different values, other sized puzzles can be solved.

The output is presented in vector form (each number represents the column position of a queen on consecutive rows). The vector can be pretty printed with this function:

def board(vec):
    '''Translate column positions to an equivalent chess board.

    >>> board([0, 4, 7, 5, 2, 6, 1, 3])
    Q-------
    ----Q---
    -------Q
    -----Q--
    --Q-----
    ------Q-
    -Q------
    ---Q----

    '''

    for col in vec:
        s = ['-'] * len(vec)
        s[col] = 'Q'
        print ''.join(s)
    print

 

With the solution represented as a vector with one queen in each row, we don’t have to check to see if two queens are on the same row. By using a permutation generator, we know that no value in the vector is repeated, so we don’t have to check to see if two queens are on the same column. Since rook moves don’t need to be checked, we only need to check bishop moves.

The technique for checking the diagonals is to add or subtract the column number from each entry, so any two entries on the same diagonal will have the same value (in other words, the sum or difference is unique for each diagnonal). Now all we have to do is make sure that the diagonals for each of the eight queens are distinct. So, we put them in a set (which eliminates duplicates) and check that the set length is eight (no duplicates were removed).

Any permutation with non-overlapping diagonals is a solution. So, we print it and continue checking other permutations.

 

這六行『派生』 Python 程式果然不同凡響,構造精妙且論理清楚。這就是 pyDatalog 解決八皇后問題的邏輯基礎。為了明白 pyDatalog 的程式,還得知道那個語言的幾件事︰

‧ 有不同『參數個數』之『同名』述詞為『不同述詞』。

‧ 『同名』述詞的多個定義是『邏輯 or 』。

‧ 『變元』是『子句參數』,其值不能自跨『子句』。

‧ 『變元值』的『引用』以『變元名』為之。

# give me all the X and Y so that X is 2 and Y is the square root of X
import math
pyDatalog.create_terms(‘math’)
print(X==2) & (Y==math.sqrt(X))

X | Y
–|————–
2 | 1.41421356237

 

‧ 『 == 』是『邏輯謂詞』,其義為『邏輯 is 』。

# give me all the X so that X is 1
print(X==1)

思、學、習其實該三位一體,缺一恐怕『所知』不牢靠,缺兩大概是『不知道』的了。這其中且以『練習』最易為『忽略』,又以『思所學』最難『精通』。故『所謂學』講的是『讀到』文本表達的『實意』,『讀出』字詞背後的『意指』是什麼,方能脈絡貫通 ,義理落實的耶!!

在此僅以一簡單程式作為閱讀 pyDatalog 八皇后問題的梯引︰

 

pi@raspberrypi ~ python3 Python 3.2.3 (default, Mar  1 2013, 11:53:50)  [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pyDatalog import pyDatalog  >>> pyDatalog.create_terms('解空間, 求解, X, Y')  # 定義 解空間 述詞 一 >>> 解空間(X) <= (X.in_(range(10))) 解空間(X) <= _pyD_in(X,'['0', '1', '2', '3', '4', '5'  # 定義 解空間 述詞 二 >>> 解空間(X, Y) <= 解空間(X) & (Y.in_(range(10))) & (Y == (7 - X)) 解空間(X,Y) <= 解空間(X)&_pyD_in(Y,'['0', '1', '2', '3',  >>> 解空間(X, Y).data [(4, 3), (5, 2), (6, 1), (7, 0), (2, 5), (1, 6), (3, 4), (0, 7)]  # 解空間 引用 >>> 求解(X, Y) <= 解空間(X, Y) & (Y == (X -3)) 求解(X,Y) <= 解空間(X,Y)&==(Y,(X-'3'))  >>> print(求解(X, Y)) X | Y --|-- 5 | 2 >>>  </pre>    <span style="color: #808000;">【範例程式】</span> <pre class="lang:sh decode:true  ">pi@raspberrypi ~ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyDatalog import pyDatalog
>>> pyDatalog.create_terms('N,X0,X1,X2,X3,X4,X5,X6,X7')
>>> pyDatalog.create_terms('ok,queens,next_queen')

>>> queens(X0)                      <= (X0._in(range(8)))
queens(X0) <= _pyD_in(X0,'['0', '1', '2', '3', '4'
>>> queens(X0,X1)                   <= queens(X0)                   & next_queen(X0,X1)
queens(X0,X1) <= queens(X0)&next_queen(X0,X1)
>>> queens(X0,X1,X2)                <= queens(X0,X1)                & next_queen(X0,X1,X2)
queens(X0,X1,X2) <= queens(X0,X1)&next_queen(X0,X1
>>> queens(X0,X1,X2,X3)             <= queens(X0,X1,X2)             & next_queen(X0,X1,X2,X3)
queens(X0,X1,X2,X3) <= queens(X0,X1,X2)&next_queen
>>> queens(X0,X1,X2,X3,X4)          <= queens(X0,X1,X2,X3)          & next_queen(X0,X1,X2,X3,X4)
queens(X0,X1,X2,X3,X4) <= queens(X0,X1,X2,X3)&next
>>> queens(X0,X1,X2,X3,X4,X5)       <= queens(X0,X1,X2,X3,X4)       & next_queen(X0,X1,X2,X3,X4,X5)
queens(X0,X1,X2,X3,X4,X5) <= queens(X0,X1,X2,X3,X4
>>> queens(X0,X1,X2,X3,X4,X5,X6)    <= queens(X0,X1,X2,X3,X4,X5)    & next_queen(X0,X1,X2,X3,X4,X5,X6)
queens(X0,X1,X2,X3,X4,X5,X6) <= queens(X0,X1,X2,X3
>>> queens(X0,X1,X2,X3,X4,X5,X6,X7) <= queens(X0,X1,X2,X3,X4,X5,X6) & next_queen(X0,X1,X2,X3,X4,X5,X6,X7)
queens(X0,X1,X2,X3,X4,X5,X6,X7) <= queens(X0,X1,X2
>>> next_queen(X0,X1)                   <= queens(X1)                       & ok(X0,1,X1)
next_queen(X0,X1) <= queens(X1)&ok(X0,'1',X1)
>>> next_queen(X0,X1,X2)                <= next_queen(X1,X2)                & ok(X0,2,X2)
next_queen(X0,X1,X2) <= next_queen(X1,X2)&ok(X0,'2
>>> next_queen(X0,X1,X2,X3)             <= next_queen(X1,X2,X3)             & ok(X0,3,X3)
next_queen(X0,X1,X2,X3) <= next_queen(X1,X2,X3)&ok
>>> next_queen(X0,X1,X2,X3,X4)          <= next_queen(X1,X2,X3,X4)          & ok(X0,4,X4)
next_queen(X0,X1,X2,X3,X4) <= next_queen(X1,X2,X3,
>>> next_queen(X0,X1,X2,X3,X4,X5)       <= next_queen(X1,X2,X3,X4,X5)       & ok(X0,5,X5)
next_queen(X0,X1,X2,X3,X4,X5) <= next_queen(X1,X2,
>>> next_queen(X0,X1,X2,X3,X4,X5,X6)    <= next_queen(X1,X2,X3,X4,X5,X6)    & ok(X0,6,X6)
next_queen(X0,X1,X2,X3,X4,X5,X6) <= next_queen(X1,
>>> next_queen(X0,X1,X2,X3,X4,X5,X6,X7) <= next_queen(X1,X2,X3,X4,X5,X6,X7) & ok(X0,7,X7)
next_queen(X0,X1,X2,X3,X4,X5,X6,X7) <= next_queen(
>>> ok(X1, N, X2) <= (X1 != X2) & (X1 != X2+N) & (X1 != X2-N)
ok(X1,N,X2) <= !=(X1,X2)&!=(X1,(X2+N))&!=(X1,(X2-N

>>> print(queens(X0,X1,X2,X3,X4,X5,X6,X7).data[0])
(2, 5, 7, 0, 4, 6, 1, 3)

>>> queens(X0,X1,X2,X3,X4,X5,X6,X7).data
[(5, 2, 0, 7, 3, 1, 6, 4), (5, 1, 6, 0, 3, 7, 4, 2), (4, 7, 3, 0, 2, 5, 1, 6), (3, 1, 7, 5, 0, 2, 4, 6), (3, 0, 4, 7, 5, 2, 6, 1), (6, 3, 1, 7, 5, 0, 2, 4), (6, 1, 3, 0, 7, 4, 2, 5), (3, 1, 6, 2, 5, 7, 0, 4), (3, 5, 7, 1, 6, 0, 2, 4), (3, 6, 0, 7, 4, 1, 5, 2), (2, 4, 1, 7, 5, 3, 6, 0), (6, 2, 0, 5, 7, 4, 1, 3), (3, 7, 0, 4, 6, 1, 5, 2), (7, 1, 3, 0, 6, 4, 2, 5), (4, 0, 7, 5, 2, 6, 1, 3), (2, 5, 1, 6, 4, 0, 7, 3), (5, 2, 6, 3, 0, 7, 1, 4), (2, 5, 1, 6, 0, 3, 7, 4), (4, 6, 3, 0, 2, 7, 5, 1), (7, 1, 4, 2, 0, 6, 3, 5), (1, 6, 2, 5, 7, 4, 0, 3), (6, 1, 5, 2, 0, 3, 7, 4), (4, 2, 7, 3, 6, 0, 5, 1), (3, 7, 4, 2, 0, 6, 1, 5), (4, 1, 7, 0, 3, 6, 2, 5), (5, 7, 1, 3, 0, 6, 4, 2), (5, 3, 0, 4, 7, 1, 6, 2), (2, 5, 7, 1, 3, 0, 6, 4), (3, 6, 4, 1, 5, 0, 2, 7), (5, 3, 1, 7, 4, 6, 0, 2), (4, 2, 0, 5, 7, 1, 3, 6), (6, 4, 2, 0, 5, 7, 1, 3), (3, 0, 4, 7, 1, 6, 2, 5), (5, 2, 6, 1, 7, 4, 0, 3), (6, 0, 2, 7, 5, 3, 1, 4), (2, 6, 1, 7, 4, 0, 3, 5), (5, 1, 6, 0, 2, 4, 7, 3), (3, 6, 2, 7, 1, 4, 0, 5), (4, 1, 3, 6, 2, 7, 5, 0), (5, 2, 6, 1, 3, 7, 0, 4), (2, 0, 6, 4, 7, 1, 3, 5), (3, 1, 6, 2, 5, 7, 4, 0), (4, 6, 1, 5, 2, 0, 3, 7), (1, 6, 4, 7, 0, 3, 5, 2), (2, 4, 1, 7, 0, 6, 3, 5), (3, 1, 4, 7, 5, 0, 2, 6), (2, 4, 7, 3, 0, 6, 1, 5), (4, 6, 0, 3, 1, 7, 5, 2), (1, 4, 6, 0, 2, 7, 5, 3), (5, 0, 4, 1, 7, 2, 6, 3), (3, 7, 0, 2, 5, 1, 6, 4), (5, 3, 6, 0, 7, 1, 4, 2), (1, 3, 5, 7, 2, 0, 6, 4), (7, 2, 0, 5, 1, 4, 6, 3), (7, 3, 0, 2, 5, 1, 6, 4), (2, 5, 7, 0, 3, 6, 4, 1), (5, 2, 4, 7, 0, 3, 1, 6), (2, 6, 1, 7, 5, 3, 0, 4), (4, 6, 1, 3, 7, 0, 2, 5), (3, 6, 4, 2, 0, 5, 7, 1), (5, 2, 0, 7, 4, 1, 3, 6), (6, 2, 7, 1, 4, 0, 5, 3), (0, 4, 7, 5, 2, 6, 1, 3), (5, 2, 0, 6, 4, 7, 1, 3), (1, 4, 6, 3, 0, 7, 5, 2), (4, 7, 3, 0, 6, 1, 5, 2), (4, 1, 3, 5, 7, 2, 0, 6), (1, 5, 0, 6, 3, 7, 2, 4), (0, 6, 3, 5, 7, 1, 4, 2), (5, 3, 6, 0, 2, 4, 1, 7), (6, 3, 1, 4, 7, 0, 2, 5), (1, 5, 7, 2, 0, 3, 6, 4), (5, 2, 4, 6, 0, 3, 1, 7), (2, 7, 3, 6, 0, 5, 1, 4), (0, 6, 4, 7, 1, 3, 5, 2), (3, 1, 6, 4, 0, 7, 5, 2), (2, 5, 3, 1, 7, 4, 6, 0), (1, 7, 5, 0, 2, 4, 6, 3), (4, 6, 1, 5, 2, 0, 7, 3), (3, 1, 7, 4, 6, 0, 2, 5), (3, 5, 0, 4, 1, 7, 2, 6), (2, 5, 1, 4, 7, 0, 6, 3), (4, 1, 5, 0, 6, 3, 7, 2), (4, 0, 3, 5, 7, 1, 6, 2), (2, 5, 3, 0, 7, 4, 6, 1), (0, 5, 7, 2, 6, 3, 1, 4), (4, 2, 0, 6, 1, 7, 5, 3), (4, 6, 0, 2, 7, 5, 3, 1), (3, 5, 7, 2, 0, 6, 4, 1), (2, 4, 6, 0, 3, 1, 7, 5), (2, 5, 7, 0, 4, 6, 1, 3), (4, 0, 7, 3, 1, 6, 2, 5)]

>>> len(queens(X0,X1,X2,X3,X4,X5,X6,X7).data)
92
>>> 

 

N 皇后範例︰

pyDatalog / pyDatalog / examples / queens_N.py

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 pyDatalog 》【專題】之約束編程‧五

曾聞小學堂的蟲食算考倒了大專生?想來其實也沒什麼奇怪!學而不思則罔,思其所學整理明辨,自有所得而且記憶長久,否則日遠時遷,早忘之矣!不會算豈不很正常!!舉例來說︰

孤獨的n

在一堆空格的數式中,剛好只有一個數字n。以下是一個「孤獨的六」:

<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \begin{matrix}<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & \Box & \Box & \Box \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \hline<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \Box & ) & \Box & \Box & \Box & \Box \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & \Box & & \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \hline<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & \Box & \Box &  \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & & \Box & \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \hline<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & & 6 & \Box \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> & & & & \Box & \Box \\<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> \end{matrix}<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />

這個孤獨的六是1053/9的直式

求解需要個下手處。那個『被除數』的千位首數必是 1 。為什麼呢 ?觀其直式除法之『商』的首數與『除式寫法』未及於『被除數』的千位首數而得知。再者那個『除數』由『商』的尾數乘法知道,只能是『7 * 9 = 63』、『8 * 8 = 64』或『9 * 7 = 63』。添上直式除法首起『兩數相乘是一位數』,可以推知『商』的首數是 1 。否則就成兩位數的了。接著推『二位數 減 一位數 等於 一位數 1 』,此 1 來於其下的直式之寫法。如此可得『被除數』首起『二位數』為 10,而且『除數』是 9 。同理『商』的十位數也必是 1 ,以及 1 □ – 9 = 6 ,所以『被除數』的十位數是 5 。故得解。

『正算反推』雖都依賴『加減乘除』的『性質』,熟悉其一,不通另一,大半因為練習多寡所致。正如《邂逅 W!o ?!》文本中講的『逆問題』

Li Bai

A Quiet Night Thought

In front of my bed, there is bright moonlight.
It appears to be frost on the ground.
I lift my head and gaze at the August Moon,
I lower my head and think of my hometown.

 

Contemplation

Moon twilight approaches, coating the ground through the window,
Resembles a touch of frost,
Moon at the window,
Taking me back to where I am from.

李白

静夜思

床前明月光
疑是地上霜
舉頭望明月
低頭思故鄉

假使將李白的《靜夜思》翻譯成英文,藉由『中英對照』,是否更能『理解』原作之『意境』呢?還是會少了點『』的『味道』??或許這個『利弊得失』就落在︰

『文化』之『盲點』,常顯現在『意義』的『忽略』之中。

『人文』之『偏見』,普遍藏於『字詞』之『情感』之內。

故而同一『內容』的多種『語言文本』,也許可見那『通常之所不見』

Inverse problem

An inverse problem is a general framework that is used to convert observed measurements into information about a physical object or system. For example, if we have measurements of the Earth’s gravity field, then we might ask the question: “given the data that we have available, what can we say about the density distribution of the Earth in that area?” The solution to this problem (i.e., the density distribution that best matches the data) is useful because it generally tells us something about a physical parameter that we cannot directly observe. Thus, inverse problems are some of the most important and well-studied mathematical problems in science and mathematics. Inverse problems arise in many branches of science and mathematics, including computer vision, natural language processing, machine learning, statistics, statistical inference, geophysics, medical imaging (such as computed axial tomography and EEG/ERP), remote sensing, ocean acoustic tomography, nondestructive testing, astronomy, physics and many other fields.

逆問題

逆 問題是一個關於如何將觀測和測量的結果轉換為物體或系統的信息的廣義框架。比如,如果我們有一個關於地球重力場的測量結果,我們就會問:「利用現有的信 息,我們能否得到地球的密度分布?」。這類問題的解(即最符合測量數據的密度分布)通常就可以告訴我們一個無法直接測量的物理量。因此,逆問題是在數學和 物理學中最重要和被研究的最多的問題之一。逆問題廣泛的出現在諸如計算機視覺,自然語言處理,機器學習,統計學,推論統計學,地理,醫學成像(比如X射線 計算機斷層成像和腦電圖/事件相關電位),遙感,海洋聲學層析,無損檢測,航空,物理學中。

 

一般所以難解之故。所謂『去除盲點』,就是『能見己所未見』之功夫。

近日偶讀楊惠后女士早年於《數學傳播》 32 卷 4 期, pp. 51-55 發表的一篇文章︰「五餅二魚」 一一談數學教學分享。略引如下︰

對一般學生而言, 若能在枯燥乏味的數學課中穿插一些有趣的、 別緻的、 與課程內容相關的益智活動, 她們會顯得很有討論的熱忱。 下面有三種文字遊戲, 我會分別安插在不同的課程內容中進行:

(a) 日本有不少學者精通漢文, 他們把中國古代詩詞中的名言佳句與「蟲食算」 結合起來, 製作了一些風格優異的小品。 遊戲規則是每題中不同的國字代表不同的阿拉伯數字, 請找出滿足這些聯立方程組的解。
1.
年年 × 歲歲 = 花相似
歲歲 ÷ 年年 = 人 ÷ 不同

2.
床前 = 明月 + 光
疑是 = 地上 × 霜

3.
舉頭 × 望 = 明月
低頭 × 思 = 故鄉

讀後頗有感觸,姑且用

床前 = 明月 + 光
疑是 = 地上 × 霜

為題,表述以 pyDatalog 求解想法,權充『約束編程』之總結。

 

pi@raspberrypi ~ $ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyDatalog import pyDatalog
>>> pyDatalog.create_terms('B, F, E, M, L, sol')
>>> pyDatalog.create_terms('月光')

>>> 月光(M,L) <= (M.in_(range(10))) & (L.in_(range(10))) & (M != L) & ( M + L >= 10)
月光(M,L) <= _pyD_in(M,'['0', '1', '2', '3', '4', '5

>>> 月光(M,L).data
[(2, 8), (7, 9), (8, 3), (6, 7), (8, 2), (7, 4), (8, 5), (7, 5), (9, 2), (6, 5), (8, 4), (7, 6), (9, 3), (6, 4), (8, 7), (8, 6), (4, 9), (9, 1), (8, 9), (9, 6), (3, 7), (9, 7), (4, 7), (5, 8), (7, 3), (9, 4), (1, 9), (4, 6), (6, 9), (9, 5), (6, 8), (2, 9), (5, 6), (4, 8), (5, 7), (3, 8), (9, 8), (3, 9), (5, 9), (7, 8)]

>>> def mod(a,b):
...     return a % b 
... 

>>> pyDatalog.create_terms('月光前, mod')

>>> 月光前(M, L, F) <= 月光(M,L) & (F.in_(range(10))) & (F != M) & (F != L) & (F == (mod(M+L, 10)))
月光前(M,L,F) <= 月光(M,L)&_pyD_in(F,'['0', '1', '2', '
>>> len(月光前(M, L, F).data)
40
>>> 月光前(M, L, F).data
[(5, 6, 1), (8, 9, 7), (7, 6, 3), (9, 4, 3), (8, 4, 2), (7, 5, 2), (4, 9, 3), (3, 8, 1), (2, 8, 0), (6, 5, 1), (4, 6, 0), (9, 8, 7), (7, 8, 5), (9, 3, 2), (3, 7, 0), (7, 9, 6), (9, 1, 0), (8, 3, 1), (9, 5, 4), (6, 9, 5), (7, 4, 1), (6, 4, 0), (7, 3, 0), (1, 9, 0), (8, 7, 5), (5, 7, 2), (5, 8, 3), (9, 2, 1), (8, 2, 0), (4, 7, 1), (8, 6, 4), (6, 8, 4), (5, 9, 4), (9, 6, 5), (3, 9, 2), (4, 8, 2), (8, 5, 3), (9, 7, 6), (2, 9, 1), (6, 7, 3)]

>>> pyDatalog.create_terms('月光前床明')

>>> 月光前床明(M,L,F,B,E) <= 月光前(M, L, F) & (E.in_(range(10))) & (E != M) & (E != L) & (E != F) &  (B.in_(range(10))) & (B != M) & (B != L) & (B != F) & (B != E) & (B == (E +1))
月光前床明(M,L,F,B,E) <= 月光前(M,L,F)&_pyD_in(E,'['0', '1

>>> len(月光前床明(M,L,F,B,E).data)
168
>>> 月光前床明(M,L,F,B,E).data
[(9, 6, 5, 3, 2), (5, 7, 2, 9, 8), (8, 2, 0, 5, 4), (6, 9, 5, 1, 0), (9, 8, 7, 1, 0), (6, 8, 4, 1, 0), (5, 9, 4, 2, 1), (9, 7, 6, 3, 2), (6, 7, 3, 1, 0), (3, 9, 2, 8, 7), (7, 6, 3, 1, 0), (7, 9, 6, 2, 1), (9, 5, 4, 8, 7), (3, 9, 2, 6, 5), (6, 9, 5, 8, 7), (9, 4, 3, 6, 5), (8, 2, 0, 4, 3), (6, 8, 4, 2, 1), (8, 7, 5, 4, 3), (4, 9, 3, 6, 5), (4, 9, 3, 8, 7), (9, 6, 5, 8, 7), (3, 9, 2, 7, 6), (8, 5, 3, 2, 1), (9, 6, 5, 4, 3), (5, 9, 4, 8, 7), (8, 2, 0, 6, 5), (8, 9, 7, 3, 2), (7, 3, 0, 5, 4), (6, 5, 1, 3, 2), (2, 8, 0, 6, 5), (7, 4, 1, 3, 2), (7, 6, 3, 2, 1), (1, 9, 0, 4, 3), (7, 9, 6, 3, 2), (7, 5, 2, 9, 8), (6, 9, 5, 4, 3), (9, 8, 7, 4, 3), (4, 6, 0, 3, 2), (8, 9, 7, 5, 4), (9, 8, 7, 2, 1), (6, 7, 3, 9, 8), (1, 9, 0, 7, 6), (5, 7, 2, 4, 3), (8, 4, 2, 7, 6), (3, 7, 0, 6, 5), (3, 8, 1, 7, 6), (5, 7, 2, 1, 0), (9, 5, 4, 2, 1), (2, 8, 0, 7, 6), (3, 9, 2, 5, 4), (7, 6, 3, 9, 8), (7, 8, 5, 4, 3), (9, 4, 3, 7, 6), (7, 4, 1, 9, 8), (8, 4, 2, 6, 5), (6, 4, 0, 2, 1), (5, 6, 1, 4, 3), (4, 6, 0, 8, 7), (1, 9, 0, 8, 7), (8, 9, 7, 6, 5), (1, 9, 0, 5, 4), (8, 5, 3, 7, 6), (3, 7, 0, 5, 4), (7, 4, 1, 6, 5), (9, 1, 0, 3, 2), (8, 3, 1, 5, 4), (9, 5, 4, 3, 2), (6, 4, 0, 9, 8), (1, 9, 0, 6, 5), (7, 3, 0, 2, 1), (3, 8, 1, 5, 4), (9, 3, 2, 6, 5), (7, 3, 0, 6, 5), (8, 3, 1, 7, 6), (5, 8, 3, 7, 6), (8, 2, 0, 7, 6), (4, 7, 1, 3, 2), (5, 6, 1, 3, 2), (3, 7, 0, 2, 1), (6, 8, 4, 3, 2), (6, 9, 5, 3, 2), (9, 7, 6, 4, 3), (9, 8, 7, 3, 2), (7, 3, 0, 9, 8), (8, 3, 1, 6, 5), (9, 7, 6, 1, 0), (4, 9, 3, 1, 0), (8, 9, 7, 1, 0), (8, 6, 4, 1, 0), (2, 9, 1, 4, 3), (8, 7, 5, 1, 0), (3, 8, 1, 6, 5), (9, 3, 2, 7, 6), (9, 8, 7, 5, 4), (2, 9, 1, 8, 7), (6, 7, 3, 5, 4), (2, 8, 0, 5, 4), (7, 6, 3, 5, 4), (5, 9, 4, 3, 2), (9, 2, 1, 7, 6), (9, 3, 2, 8, 7), (9, 6, 5, 1, 0), (9, 3, 2, 5, 4), (9, 7, 6, 5, 4), (4, 7, 1, 6, 5), (7, 9, 6, 4, 3), (4, 9, 3, 2, 1), (8, 9, 7, 4, 3), (7, 9, 6, 1, 0), (8, 6, 4, 2, 1), (8, 7, 5, 2, 1), (4, 6, 0, 9, 8), (7, 8, 5, 3, 2), (9, 8, 7, 6, 5), (8, 4, 2, 1, 0), (9, 1, 0, 8, 7), (2, 8, 0, 4, 3), (9, 2, 1, 8, 7), (9, 6, 5, 2, 1), (7, 8, 5, 1, 0), (6, 5, 1, 9, 8), (9, 2, 1, 5, 4), (9, 1, 0, 6, 5), (9, 4, 3, 1, 0), (7, 9, 6, 5, 4), (4, 8, 2, 7, 6), (2, 9, 1, 5, 4), (2, 9, 1, 7, 6), (9, 3, 2, 1, 0), (4, 6, 0, 2, 1), (6, 9, 5, 2, 1), (4, 8, 2, 6, 5), (5, 8, 3, 1, 0), (9, 1, 0, 4, 3), (9, 2, 1, 4, 3), (3, 9, 2, 1, 0), (9, 4, 3, 8, 7), (4, 8, 2, 1, 0), (9, 5, 4, 1, 0), (6, 4, 0, 3, 2), (8, 9, 7, 2, 1), (4, 7, 1, 9, 8), (6, 4, 0, 8, 7), (9, 2, 1, 6, 5), (5, 6, 1, 8, 7), (9, 1, 0, 7, 6), (9, 4, 3, 2, 1), (9, 5, 4, 7, 6), (2, 9, 1, 6, 5), (6, 5, 1, 4, 3), (4, 9, 3, 7, 6), (9, 1, 0, 5, 4), (9, 7, 6, 2, 1), (5, 9, 4, 1, 0), (7, 8, 5, 2, 1), (8, 6, 4, 3, 2), (7, 5, 2, 4, 3), (8, 7, 5, 3, 2), (6, 7, 3, 2, 1), (7, 5, 2, 1, 0), (6, 5, 1, 8, 7), (5, 8, 3, 2, 1), (5, 6, 1, 9, 8), (5, 9, 4, 7, 6), (1, 9, 0, 3, 2), (8, 5, 3, 1, 0), (3, 7, 0, 9, 8)]

>>> pyDatalog.create_terms('疑是地上霜, S, I, G, U, Z')

>>> pyDatalog.create_terms('地上霜')

>>> 地上霜(G, U, Z) <=  (G.in_(range(10))) &  (U.in_(range(10))) &  (Z.in_(range(10))) & (G != U) & (G != Z) & (U !=Z) & (((10*G +U)*Z) < 100)
地上霜(G,U,Z) <= _pyD_in(G,'['0', '1', '2', '3', '4',

>>> len(地上霜(G, U, Z).data)
279

>>> 疑是地上霜(S,I,G,U,Z) <= 地上霜(G, U, Z) & (S.in_(range(10))) & (S != G) & (S != U) & (S != Z) & (I.in_(range(10))) & (I != G) & (I != U) & (I != Z) & (I != S) & (I == (10*G*Z + U*Z - 10*S)) 
疑是地上霜(S,I,G,U,Z) <= 地上霜(G,U,Z)&_pyD_in(S,'['0', '1

>>> len(疑是地上霜(S,I,G,U,Z).data)
63
>>> 疑是地上霜(S,I,G,U,Z).data
[(2, 7, 0, 9, 3), (1, 6, 0, 8, 2), (7, 8, 3, 9, 2), (5, 6, 0, 7, 8), (1, 8, 0, 6, 3), (1, 2, 0, 3, 4), (2, 1, 0, 3, 7), (5, 7, 1, 9, 3), (1, 8, 0, 2, 9), (2, 7, 0, 3, 9), (7, 6, 1, 9, 4), (3, 6, 1, 8, 2), (9, 0, 1, 8, 5), (8, 6, 4, 3, 2), (2, 4, 0, 8, 3), (9, 8, 1, 4, 7), (5, 4, 0, 6, 9), (5, 4, 1, 8, 3), (3, 2, 0, 4, 8), (1, 8, 0, 3, 6), (3, 6, 0, 4, 9), (2, 8, 0, 4, 7), (9, 0, 1, 5, 6), (5, 4, 0, 9, 6), (3, 4, 1, 7, 2), (6, 8, 1, 7, 4), (5, 2, 1, 3, 4), (7, 8, 2, 6, 3), (3, 6, 0, 9, 4), (3, 2, 0, 8, 4), (8, 4, 1, 2, 7), (8, 1, 2, 7, 3), (2, 4, 0, 3, 8), (7, 2, 1, 8, 4), (7, 8, 1, 3, 6), (9, 0, 4, 5, 2), (9, 6, 4, 8, 2), (7, 6, 3, 8, 2), (1, 8, 0, 9, 2), (1, 4, 0, 7, 2), (6, 3, 0, 7, 9), (3, 0, 1, 5, 2), (7, 2, 0, 8, 9), (2, 1, 0, 7, 3), (1, 2, 0, 4, 3), (4, 2, 0, 6, 7), (6, 0, 1, 2, 5), (4, 2, 0, 7, 6), (7, 0, 1, 4, 5), (7, 2, 0, 9, 8), (2, 8, 0, 7, 4), (6, 0, 1, 5, 4), (8, 7, 2, 9, 3), (8, 0, 1, 6, 5), (9, 6, 1, 2, 8), (6, 3, 0, 9, 7), (1, 6, 0, 2, 8), (4, 8, 1, 6, 3), (5, 6, 0, 8, 7), (1, 4, 0, 2, 7), (7, 0, 3, 5, 2), (6, 8, 3, 4, 2), (3, 8, 1, 9, 2)]

>>> sol(M,L,F,B,E,S,I,G,U,Z) <= 月光前床明(M,L,F,B,E) & 疑是地上霜(S,I,G,U,Z) & (S != M) & (S != L) & (S != F) & (S != B) & (S != E) & (I != M) & (I != L) & (I != F) & (I != B) & (I != E) & (G != M) & (G != L) & (G != F) & (G != B) & (G != E) & (U != M) & (U != L) & (U != F) & (U != B) & (U != E) & (Z != M) & (Z != L) & (Z != F) & (Z != B) & (Z != E)
sol(M,L,F,B,E,S,I,G,U,Z) <= 月光前床明(M,L,F,B,E)&疑是地上霜

>>> print(sol(M,L,F,B,E,S,I,G,U,Z))
M | L | F | B | E | S | I | G | U | Z
--|---|---|---|---|---|---|---|---|--
7 | 6 | 3 | 5 | 4 | 1 | 8 | 0 | 9 | 2
9 | 6 | 5 | 8 | 7 | 1 | 2 | 0 | 3 | 4
9 | 4 | 3 | 2 | 1 | 5 | 6 | 0 | 7 | 8
8 | 9 | 7 | 6 | 5 | 1 | 2 | 0 | 3 | 4
1 | 9 | 0 | 5 | 4 | 7 | 8 | 2 | 6 | 3
6 | 9 | 5 | 8 | 7 | 1 | 2 | 0 | 4 | 3
8 | 7 | 5 | 2 | 1 | 3 | 6 | 0 | 9 | 4
6 | 9 | 5 | 8 | 7 | 1 | 2 | 0 | 3 | 4
6 | 5 | 1 | 4 | 3 | 7 | 2 | 0 | 8 | 9
9 | 5 | 4 | 1 | 0 | 7 | 6 | 3 | 8 | 2
2 | 9 | 1 | 4 | 3 | 5 | 6 | 0 | 8 | 7
4 | 9 | 3 | 2 | 1 | 5 | 6 | 0 | 7 | 8
9 | 1 | 0 | 5 | 4 | 7 | 8 | 2 | 6 | 3
4 | 9 | 3 | 2 | 1 | 5 | 6 | 0 | 8 | 7
8 | 9 | 7 | 3 | 2 | 6 | 0 | 1 | 5 | 4
7 | 6 | 3 | 5 | 4 | 1 | 8 | 0 | 2 | 9
3 | 9 | 2 | 8 | 7 | 6 | 0 | 1 | 5 | 4
9 | 8 | 7 | 6 | 5 | 1 | 2 | 0 | 3 | 4
3 | 7 | 0 | 5 | 4 | 9 | 6 | 1 | 2 | 8
4 | 9 | 3 | 8 | 7 | 6 | 0 | 1 | 2 | 5
9 | 4 | 3 | 8 | 7 | 6 | 0 | 1 | 2 | 5
9 | 5 | 4 | 1 | 0 | 7 | 8 | 2 | 6 | 3
8 | 9 | 7 | 6 | 5 | 1 | 2 | 0 | 4 | 3
6 | 5 | 1 | 4 | 3 | 7 | 2 | 0 | 9 | 8
9 | 8 | 7 | 6 | 5 | 1 | 2 | 0 | 4 | 3
8 | 7 | 5 | 2 | 1 | 3 | 6 | 0 | 4 | 9
6 | 7 | 3 | 5 | 4 | 1 | 8 | 0 | 2 | 9
9 | 2 | 1 | 4 | 3 | 5 | 6 | 0 | 7 | 8
9 | 8 | 7 | 4 | 3 | 6 | 0 | 1 | 2 | 5
8 | 9 | 7 | 4 | 3 | 6 | 0 | 1 | 2 | 5
7 | 8 | 5 | 2 | 1 | 3 | 6 | 0 | 9 | 4
9 | 4 | 3 | 2 | 1 | 5 | 6 | 0 | 8 | 7
9 | 6 | 5 | 8 | 7 | 1 | 2 | 0 | 4 | 3
9 | 8 | 7 | 3 | 2 | 6 | 0 | 1 | 5 | 4
5 | 6 | 1 | 4 | 3 | 7 | 2 | 0 | 9 | 8
1 | 9 | 0 | 5 | 4 | 7 | 6 | 3 | 8 | 2
5 | 9 | 4 | 1 | 0 | 7 | 6 | 3 | 8 | 2
5 | 6 | 1 | 4 | 3 | 7 | 2 | 0 | 8 | 9
5 | 9 | 4 | 1 | 0 | 7 | 8 | 2 | 6 | 3
7 | 8 | 5 | 2 | 1 | 3 | 6 | 0 | 4 | 9
2 | 9 | 1 | 4 | 3 | 5 | 6 | 0 | 7 | 8
9 | 1 | 0 | 5 | 4 | 7 | 6 | 3 | 8 | 2
9 | 3 | 2 | 8 | 7 | 6 | 0 | 1 | 5 | 4
3 | 8 | 1 | 7 | 6 | 9 | 0 | 4 | 5 | 2
7 | 3 | 0 | 5 | 4 | 9 | 6 | 1 | 2 | 8
8 | 3 | 1 | 7 | 6 | 9 | 0 | 4 | 5 | 2
6 | 7 | 3 | 5 | 4 | 1 | 8 | 0 | 9 | 2
9 | 2 | 1 | 4 | 3 | 5 | 6 | 0 | 8 | 7
>>> 

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 pyDatalog 》【專題】之約束編程‧四

假使我們在樹莓派 2B 上,嘗試用『蠻力法』求解『亨利‧杜德耐』Henry Dudeney 於一九二四年,在 Strand Magazine 所發表的『SEND + MORE = MONEY』的問題︰

SendMoreMoney

sol(S,E,N,D,M,O,R,Y) <=

(S.in_(range(1,10))) & (E.in_(range(10))) & (N.in_(range(10))) & (D.in_(range(10))) & (M.in_(range(1,10))) & (O.in_(range(10))) & (R.in_(range(10))) & (Y.in_(range(10))) &

(S != E) &(S != N) & (S != D) & (S != M) & (S != O) & (S != R) & (S !=Y) &
(E != N) & (E != D) & (E != M) & (E != O) & (E != R) & (E != Y) &
(N != D) & (N != M) & (N != O) & (N != R) & (N != Y) &
(D != M) & (D != O) & (D != R) & (D != Y) &
(M != O) & (M != R) & (M != Y) &
(O != R) & (O != Y) &
(R != Y) &

( M == (((S-O)*1000 + (E+O-N)*100 +(N+R-E)*10 + (E+D-Y)) / 9000))

,你將會遭遇到 python3 解譯器『記憶爆炸』的現象。這事可令人覺得驚訝,才八個變元,就把系統搞掛了耶?如果想想搜尋空間有 10^6 \times 9^2 \ = \ 81 M 這麼大,也許那結果就不奇怪的了。這也說明了『分析問題』的重要性。比方說,從直式加法

S + M = MO

條件裡,我們可以得出

M = 1 因 S 或 M 最大是 9 , 即使加上前項的進位也小於 20 之故。

S = 9 ,因已得 M = 1 ,而且 S + M >= 10 之故。

即使我們將這個所知放到 osol 述詞裡︰

osol(S,E,N,D,M,O,R,Y) <=

(S == 9) &

(E.in_(range(10))) & (N.in_(range(10))) & (D.in_(range(10))) &

(M == 1) &

(O.in_(range(10))) & (R.in_(range(10))) & (Y.in_(range(10))) &

(S != E) &(S != N) & (S != D) & (S != M) & (S != O) & (S != R) & (S !=Y) & (E != N) & (E != D) & (E != M) & (E != O) & (E != R) & (E != Y) & (N != D) & (N != M) & (N != O) & (N != R) & (N != Y) & (D != M) & (D != O) & (D != R) & (D != Y) & (M != O) & (M != R) & (M != Y) & (O != R) & (O != Y) & (R != Y) &

( M == (((S-O)*1000 + (E+O-N)*100 +(N+R-E)*10 + (E+D-Y)) / 9000))

,卻依然『記憶體不足』而當掉。如此可以知道 pyDatalog 運算時所需的記憶體之大的了。事實上從上式,我們還可以推知 O = 0 ,因 O != SO != M ,就算進位也只能多 1 之故。加上這個事實後,勉強可以算得了答案︰

 

pi@raspberrypi ~ python3 Python 3.2.3 (default, Mar  1 2013, 11:53:50)  [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pyDatalog import pyDatalog >>> pyDatalog.create_terms('S,E,N,D,M,O,R,Y,sol')  >>> sol(E,N,D,O,R,Y) <= (E.in_(range(10))) & (N.in_(range(10))) & (D.in_(range(10))) & (O.in_(range(2))) & (R.in_(range(10))) & (Y.in_(range(10))) & (E != 1) & (E !=9) & (E != N) & (E != D) & (E != O) & (E != R) & (E != Y) & (N != 1) & (N != 9) & (N != D) & (N != O) & (N != R) & (N != Y) & (D != 1) & (D != 9) & (D != O) & (D != R) & (D != Y) & (O !=1) & (O !=9) & (O != R) & (O != Y) & (R != 1) & (R != 9) & (R != Y) & (Y !=1) & (Y !=9) & (Y == ((9-O)*1000 + (E+O-N)*100 + (N+R-E)*10 + (D+E) - 9000 )) sol(E,N,D,O,R,Y) <= _pyD_in(E,'['0', '1', '2', '3'  >>> print(sol(E,N,D,O,R,Y)) E | N | D | O | R | Y --|---|---|---|---|-- 5 | 6 | 7 | 0 | 8 | 2 >>>  </pre>    這說明了『分析問題』的好處。假使再添上直式加法裡  <span style="font-family: LinBiolinum_K;">D + E  = [0 | 1] Y</span>  的條件,且用 mod 述詞表達為  Y == mod( (D+E), 10 )  。我們將可以定義一個 deyspace 述詞  <span style="color: #808080;"> deyspace(D,E,Y) <= </span>  <span style="color: #808080;">(D.in_((2,3,4,5,6,7,8))) & </span>  <span style="color: #808080;">(E.in_((2,3,4,5,6,7,8))) & </span>  <span style="color: #808080;">(Y.in_((2,3,4,5,6,7,8))) & </span>  <span style="color: #808080;">(D != E) & (D != Y) & (E != Y) & </span>  <span style="color: #808080;">(Y == mod((D+E),10))</span>  大幅縮小搜尋空間以及提昇程式執行速度。  【參考程式】 <pre class="lang:sh decode:true   ">pi@raspberrypi ~ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyDatalog import pyDatalog
>>> pyDatalog.create_terms('S,E,N,D,M,O,R,Y,sol')
>>> def mod(a,b):
...     return a % b
... 
>>> pyDatalog.create_terms('mod')
>>> pyDatalog.create_terms('deyspace')

>>> deyspace(D,E,Y) <= (D.in_((2,3,4,5,6,7,8))) & (E.in_((2,3,4,5,6,7,8))) & (Y.in_((2,3,4,5,6,7,8))) & (D != E) & (D != Y) & (E != Y) & (Y == mod((D+E),10))
deyspace(D,E,Y) <= _pyD_in(D,'['2', '3', '4', '5',
>>> len(deyspace(D,E,Y).data)
24
>>> print(deyspace(D,E,Y))
D | E | Y
--|---|--
8 | 5 | 3
3 | 2 | 5
6 | 8 | 4
2 | 5 | 7
7 | 6 | 3
2 | 6 | 8
6 | 2 | 8
5 | 3 | 8
2 | 3 | 5
8 | 7 | 5
6 | 7 | 3
5 | 2 | 7
2 | 4 | 6
7 | 5 | 2
5 | 7 | 2
7 | 8 | 5
8 | 6 | 4
4 | 3 | 7
3 | 5 | 8
4 | 8 | 2
8 | 4 | 2
5 | 8 | 3
3 | 4 | 7
4 | 2 | 6

>>> sol(E,N,D,R,Y) <= deyspace(D,E,Y) & (N.in_(range(10))) & (R.in_(range(10)))  & (E != N) & (E != R) & (N != 1) & (N != 9) & (N !=0) & (N != D) & (N != R) & (N != Y) & (D != R)  & (R != 1) & (R != 9) & (R != 0) & (R != Y)  & (Y == ((E-N)*100 + (N+R-E)*10 + (D+E) ))
sol(E,N,D,R,Y) <= deyspace(D,E,Y)&_pyD_in(N,'['0',

>>> print(sol(E,N,D,R,Y))
E | N | D | R | Y
--|---|---|---|--
5 | 6 | 7 | 8 | 2
>>> 

 

所以說純靠『蠻力』還是可能不足的,若是『窮舉』加上『智力』力量怕是大的多哩!對於『 語詞方程式 』解題要點有興趣的讀者,可以上網讀讀《  A PRIMER ON CRYPTARITHMETIC 》,相信能有不少的收穫呦。

 

 

 

 

 

 

 

勇闖新世界︰ 《 pyDatalog 》【專題】之約束編程‧三

窮舉法』是一種通用方法。它以『問題』為『解』之『對錯』的『判準』,窮盡『所有可能』的『解』作『斷言』之求解法。或可同時參閱《 M♪o 之學習筆記本《寅》井井︰【䷝】試釋是事》文中所說之『蠻力法』以及例子︰

行 ︰雖說是蠻力法,實則乃用『窮舉』,數ㄕㄨˇ數ㄕㄨˋ數不盡,耗時難為功,怎曉 機 機心迅捷後,此法遂真可行耶!?實習所用機,登入採『學號』與『針碼』【※ Pin Code 四位數字碼】。『學號』之制 ── 班碼-位碼 ──,班不過十,位少於百,故而極其數不足千。針碼有四位,總其量,只有萬。試而盡之,『千萬』已『窮舉』。問題當在『咸澤碼訊』有多快?『登錄』之法有 多嚴 ?破解程式幾人會?設使一應具足,那個『駭黑』之事,怕是恐難免!!……

此處特別指出計算機『速度提昇』使得『窮舉法』的實用性大增,對此法的了解也就更顯得重要了。

假使將『所有可能解』看成『解空間』,將『問題』當成『約束』條件,此時『問題』的『求解』,就轉換成『尋找』『解空間』中滿足『約束』條件的『解』。一般將之稱為『蠻力搜尋法』︰

Brute-force search

In computer science, brute-force search or exhaustive search, also known as generate and test, is a very general problem-solving technique that consists of systematically enumerating all possible candidates for the solution and checking whether each candidate satisfies the problem’s statement.

A brute-force algorithm to find the divisors of a natural number n would enumerate all integers from 1 to the square root of n, and check whether each of them divides n without remainder. A brute-force approach for the eight queens puzzle would examine all possible arrangements of 8 pieces on the 64-square chessboard, and, for each arrangement, check whether each (queen) piece can attack any other.

While a brute-force search is simple to implement, and will always find a solution if it exists, its cost is proportional to the number of candidate solutions – which in many practical problems tends to grow very quickly as the size of the problem increases. Therefore, brute-force search is typically used when the problem size is limited, or when there are problem-specific heuristics that can be used to reduce the set of candidate solutions to a manageable size. The method is also used when the simplicity of implementation is more important than speed.

This is the case, for example, in critical applications where any errors in the algorithm would have very serious consequences; or when using a computer to prove a mathematical theorem. Brute-force search is also useful as a baseline method when benchmarking other algorithms or metaheuristics. Indeed, brute-force search can be viewed as the simplest metaheuristic. Brute force search should not be confused with backtracking, where large sets of solutions can be discarded without being explicitly enumerated (as in the textbook computer solution to the eight queens problem above). The brute-force method for finding an item in a table — namely, check all entries of the latter, sequentially — is called linear search.

上一篇因數的例子︰

 

pi@raspberrypi ~ python3 Python 3.2.3 (default, Mar  1 2013, 11:53:50)  [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pyDatalog import pyDatalog  >>> pyDatalog.create_terms('X被除數, Y除數, Q商, R餘數, 被除數空間, 除數空間')  >>> 被除數空間(X被除數) <= (X被除數.in_(range(100))) 被除數空間(X被除數) <= _pyD_in(X被除數,'['0', '1', '2', '3',   >>> 被除數空間(X被除數) .data [(47,), (97,), (28,), (94,), (9,), (75,), (6,), (56,), (53,), (34,), (31,), (81,), (12,), (78,), (59,), (40,), (37,), (18,), (84,), (15,), (65,), (62,), (43,), (24,), (90,), (21,), (87,), (2,), (68,), (49,), (46,), (96,), (27,), (93,), (8,), (74,), (5,), (71,), (52,), (33,), (99,), (30,), (80,), (11,), (77,), (58,), (55,), (36,), (17,), (83,), (14,), (64,), (61,), (42,), (39,), (89,), (20,), (86,), (1,), (67,), (48,), (45,), (26,), (92,), (23,), (73,), (4,), (70,), (51,), (32,), (98,), (29,), (95,), (10,), (76,), (7,), (57,), (54,), (35,), (16,), (82,), (13,), (79,), (60,), (41,), (38,), (88,), (19,), (85,), (0,), (66,), (63,), (44,), (25,), (91,), (22,), (72,), (3,), (69,), (50,)]  >>> 除數空間(X被除數, Y除數) <= 被除數空間(X被除數) & (Y除數.in_(range(1, 100))) & (Y除數 <= X被除數) 除數空間(X被除數,Y除數) <= 被除數空間(X被除數)&_pyD_in(Y除數,'['1', '  >>> 除數空間(20, Y除數) [(13,), (3,), (12,), (2,), (15,), (5,), (14,), (4,), (17,), (7,), (16,), (6,), (19,), (9,), (18,), (8,), (11,), (20,), (1,), (10,)]  >>> len(除數空間(20, Y除數).data) 20  >>> pyDatalog.create_terms('除法等式')  >>> def 餘數(a, b): ...     return a % b ...   >>> pyDatalog.create_terms('餘數')  >>> 除法等式(X被除數,Y除數, Q商, R餘數) <= 除數空間(X被除數, Y除數) & (Q商 == (X被除數 // Y除數)) & (R餘數 == 餘數(X被除數,Y除數)) 除法等式(X被除數,Y除數,Q商,R餘數) <= 除數空間(X被除數,Y除數)&==(Q商,(X被除  >>> 除法等式(20,Y除數, Q商, R餘數) [(18, 1, 2), (14, 1, 6), (7, 2, 6), (8, 2, 4), (16, 1, 4), (15, 1, 5), (2, 10, 0), (9, 2, 2), (1, 20, 0), (12, 1, 8), (19, 1, 1), (4, 5, 0), (13, 1, 7), (17, 1, 3), (5, 4, 0), (3, 6, 2), (6, 3, 2), (20, 1, 0), (11, 1, 9), (10, 2, 0)]  >>> 除法等式(20,Y除數, Q商, 0) [(4, 5), (1, 20), (5, 4), (2, 10), (10, 2), (20, 1)] >>>  >>> pyDatalog.create_terms('因數, F因子')  >>> 因數(X被除數, F因子) <= 除法等式(X被除數, F因子, Q商, 0) 因數(X被除數,F因子) <= 除法等式(X被除數,F因子,Q商,'0')  >>> 因數(20, F因子) [(10,), (5,), (4,), (1,), (20,), (2,)]  >>> 因數(X被除數, F因子) <= 除法等式(X被除數, Y除數, F因子, 0) 因數(X被除數,F因子) <= 除法等式(X被除數,Y除數,F因子,'0')  >>> 因數(20, F因子) [(20,), (1,), (4,), (5,), (10,), (2,)] >>>   >>> pyDatalog.create_terms('因式分解除法')  >>> import math >>> pyDatalog.create_terms('math')  >>> 因式分解除法(X被除數,Y除數, Q商, R餘數) <= 除數空間(X被除數, Y除數) & (Y除數 <= (math.sqrt(X被除數) + 1)) & (Q商 == (X被除數 // Y除數)) & (R餘數 == 餘數(X 被除數,Y除數)) 因式分解除法(X被除數,Y除數,Q商,R餘數) <= 除數空間(X被除數,Y除數)&<=(Y除數,(  >>> 因式分解除法(20,Y除數, Q商, R餘數) [(1, 20, 0), (4, 5, 0), (3, 6, 2), (5, 4, 0), (2, 10, 0)]  >>> 因式分解除法(20,Y除數, Q商, 0) [(5, 4), (4, 5), (1, 20), (2, 10)]  >>> pyDatalog.create_terms('因數一')  >>> 因數一(X被除數, F因子) <= 因式分解除法(X被除數, F因子, Q商, 0) 因數一(X被除數,F因子) <= 因式分解除法(X被除數,F因子,Q商,'0')  >>> 因數一(20, F因子) [(4,), (1,), (2,), (5,)]  >>> 因數一(X被除數, F因子) <= 因式分解除法(X被除數, Y除數, F因子, 0) 因數一(X被除數,F因子) <= 因式分解除法(X被除數,Y除數,F因子,'0')  >>> 因數一(20, F因子) [(4,), (5,), (10,), (2,), (20,), (1,)] >>>  </pre>    其實用的就是此『 generate and test 』生成‧驗證之法。由於此法『邏輯』單純,用『邏輯編程』容易,最要緊的事情,反倒是如何從『問題分析』裡,得到『小的解空間』、形成『適當約束條件』以及『正確』使用 pyDatalog 的『語法』來作表達的了。  就讓我們從一個『語詞方程式』  <span style="color: #ff9900;">I * AM = SAM</span>  <span style="color: #808080;">【※ I、A、S、M 都是十進制數字,不同的字母所代表之數字不同 。I 是一位數、AM 是兩位數、SAM 是三位數,一般領頭數字不為零。『*』是乘法。】</span>  展開討論。如果沒有其它的條件,我們可以用典型『蠻力法』述詞來求解︰<span style="color: #808080;">【※ 注意!變元._in 和 變元._in 意義相同嗎?】</span>  <span style="color: #ff9900;">sol(I,A,M,S) <=</span>  <span style="color: #ff9900;">(I._in(range(10))) & (A._in(range(10))) &</span> <span style="color: #ff9900;"> (M._in(range(10))) &(S._in(range(10))) & </span>  <span style="color: #ff9900;">(I != 0) & (A !=0) & (S !=0) &</span> <span style="color: #ff9900;"> (I != A) & (I != M) & (I != S) &</span> <span style="color: #ff9900;"> (A != M) & (A !=S) &</span> <span style="color: #ff9900;"> (M !=S) & </span>  <span style="color: #ff9900;">(I == ((100*S + 10*A + M) / (10*A +M)))</span>  【程式如下】 <pre class="lang:sh decode:true    ">pi@raspberrypi ~ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyDatalog import pyDatalog

>>> pyDatalog.create_terms('I,A,M,S,d,sol')

>>> sol(I,A,M,S) <= (I._in(range(10))) & (A._in(range(10))) & (M._in(range(10))) &(S._in(range(10))) &(I != 0) & (A !=0) & (I != A) & (I != M) & (I != S) & (A != M) & (A !=S) & (M !=S) & (I == ((100*S + 10*A + M) / (10*A +M)))
sol(I,A,M,S) <= _pyD_in(I,'['0', '1', '2', '3', '4

>>> print(sol(I,A,M,S))
I | A | M | S
--|---|---|--
7 | 5 | 0 | 3
3 | 5 | 0 | 1
9 | 5 | 0 | 4
6 | 4 | 0 | 2
9 | 7 | 5 | 6
6 | 2 | 0 | 1
6 | 8 | 0 | 4
>>>

 

那麼我們能不能更深入『了解問題』,然後將程式改寫的更『好』的呢?當然『好』可以有多種標準,對於『計算機科學』來講,『□□最佳化』是最主要的依歸。有興趣的讀者可以閱讀

Approximating Constraint Propagation in Datalog

We present a technique exploiting Datalog with aggregates to improve the performance of programs with arithmetic (in)equalities. Our approach employs a source-to-source program transformation which approximates the propagation technique from Constraint Programming. The experimental evaluation of the approach shows good run time speed-ups on a range of non-recursive as well as recursive programs. Furthermore, our technique improves upon the previously reported in the literature constraint magic set transformation approach.

之論文,得到一些啟發。