計算幾何 - HW02

Chapter 3

3.2

A rectilinear polygon is a simple polygon of which all edges are horizontal or vertical. Let P be a rectilinear polygon with n vertices. Give an example to show that $\left \lfloor n/4 \right \rfloor$ cameras are sometimes necessary to guard it.


正交多邊形是其中一種多邊形,邊與邊之間不是平行就是垂直。至少需要 n/4 個攝影機才能監視每一個角落。

The rectilnear polygon would contain $\left \lfloor n/4 \right \rfloor$ parallel “alleys”. At least $\left \lfloor n/4 \right \rfloor$ cameras are needed because no cameras can see more than one alleys.

正交多邊形,可以產生 $\left \lfloor n/4 \right \rfloor$ 個平行的走廊,每一個攝影機只能顧及一個走廊,因此得到一個最簡單的例子需要 $\left \lfloor n/4 \right \rfloor$ 個攝影機。

3.7

Let P be a simple polygon with n vertices, which has been partitioned into monotone pieces. Prove that the sum of the number of vertices of the pieces is O(n).


證明一個 n 個節點的簡單多邊形,拆成多個 monotone pieces,節點總數仍然是 O(n)。

一個簡單多邊形可以三角化成 n - 2 個三角形,每個三角形都是一個 monotone piece,因此節點個數總和 $3 * (n - 2) = O(n)$

證明一個簡單多邊形有 n 個頂點,可以切成 n - 2 個三角形。

  • n = 3 時,T(3) = 1, 符合 T(n) = n - 2 成立
  • 當 n = k 時,k >= 3, 且符合 T(n) = n - 2
  • n = k + 1 時,T(n + 1) = T(n) + 1 = (n - 2) + 1 = n - 1,

切割的證明為,找到多邊形的最左側點,然後他一定是凸的,將相鄰兩點拉一條線,如果構成的三角形內部沒有其他點,則直接變成 n - 1 個節點的多邊形,如果裡面有點,則挑一個最靠近最左側點的那個點,將最左側那個點與其相連,這時劃分成兩個多邊形,保證算法一樣。

3.11

Give an efficient algorithm to determine whether a polygon P with n
vertices is monotone with respect to some line, not necessarily a horizontal
or vertical one.


請參考 [ACM 題目] 單調測試 的解法。

主要解法複雜度為 O(n log n),採用角度掃描。

Chapter 4

4.2

Consider the casting problem in the plane: we are given polygon P and a 2-dimensional mold for it. Describe a linear time algorithm that decides whether P can be removed from the mold by a single translation.


  1. 對於 P 的任一面 $f_{i}$ 的法向量 $\vec{n_{i}}$,找到一個移動向量 $\vec{d}$,使其 $\vec{n_{i}}$$\vec{d}$ 張角全大於 90 度。也就是內積小於 0。
  2. 給 {(n1x, n1y), (n2x, n2y), …}
    nix * dx + niyy * dy <= 0

  3. 如果不單純派 dy = 1,調用 2DRANDOMIZEDBOUNDLP 判斷是否有解即可,不必最佳化其結果。

4.8

The plane z = 1 can be used to represent all directions of vectors in 3-dimensional space that have a positive z-value. How can we represent all directions of vectors in 3-dimensional space that have a non-negative z-value? And how can we represent the directions of all vectors in 3-dimensional space?


  1. $z = 0 \cup z = 1$
  2. $z = -1 \cup z = 1 \cup x = -1 \cup x = 1 \cup y = -1 \cup y = 1$,有人問說單純 $z = -1 \cup z = 1$ 不就包含了所有方向嗎?但是我思考了一下收斂問題,這之間到底有沒有連續?極限上是相同,但是包不包含呢?這一點我比較擔憂,總之找一個方法將原點包起,保證原點拉到任一個面都能產生出所有方向,我附的答案是六面體,最簡單的四面體都然也可以,但是不太好寫。

4.16

On n parallel railway tracks n trains are going with constant speeds v1, v2, . . . , vn. At time t = 0 the trains are at positions k1, k2, . . . , kn. Give an O(nlogn) algorithm that detects all trains that at some moment in time are leading. To this end, use the algorithm for computing the intersection of half-planes.


  • 公式:$X_{i}(t) = K_{i} + V_{i} * t$
  • 對於所有 polyhedral set $H = {(t, x) : \forall i; X \geq X_{i}(t)}$

之後將這些半平面做交集,看交集結果的邊屬於哪一個半平面的邊界,哪一個火車就曾經領先過。套用半平面求交集只需要 O(n log n)

請參考 [ACM 題目] 少女與戰車

Read More +

[通識] 文明的進程 Week 4

每次小考禮貌與羞恥相關的考題,看來這門通識相當難過呢。

文明相對性

文明化是具有相對性的,根據不同時間,原本認為好的文明舉止也有可能被汰換掉,而不好的舉止也有可能再下一個世代中被重用。

舉一個最簡單的例子,以我們亞洲社會來講,一個溫文儒雅、拘謹的人才算文明,而在過去可能認為瀟灑自在、豪放不羈才算是一個文明俠士。在這一個過程中,文明舉止居然變得不文明,是個相當有趣的現象。

看看那電影中的英雄,有多少文明人呢?個個不守規矩,個個都有反抗意識。還做英雄?還是做文明人?

文明阻隔

文明舉止阻隔了什麼?身為一個生物的 自然功能 (Elias 書中特地不寫 屎尿屁 ),現代人眼中講出 屎尿屁 三字的羞恥程度居然沒有比過去還要高,Elias 的年代講出這幾個字想必都羞愧不如。

進食 可以忍耐、延後,但是屎尿屁三者卻是相當難抑制。人都不人,這正常功能卻要被約束,抑制反而會傷了身體,為了禮儀而傷了自己,在現代則盡可能以 健康為由 ,走向與禮儀相反的舉止,盡可能轉換這一過程。

論廁所

廁所越來越不像廁所,越來越隱密,越隱密就越受歡迎,相反的卻也越來越不環保,為了在空氣流通不好的地方保持流通,消耗更多電力來維護。

當人們越常在外活動,公廁的存在就很重要,因此用公廁的普遍性呈現一個國家的文明程度,

在鄉下的農業社會中,鄉民們還會替你準備公廁呢,「 你的屎尿就是黃金肥料 」 化學肥料沒有普及到那邊時,屎尿可能比黃金更珍貴,因此處處可見這種由農民建起的公廁,而有誤解成中國為 “禮儀之邦”,人的屎尿不會隨處可見,反觀歐洲在下水道還沒有技術支持前,人的屎尿在街道上到處都是,相較中國反而文明了!

規範手法

  • 外顯禮貌
  • 內在羞恥

其中羞恥心為最重要的手法,尤其是當沒有別人眼光時,仍然要遵守禮儀就是相當需要羞恥心的。

「小天使會在一旁看著,如果不想讓天使討厭你,請隨時注意禮節。」而在現在監視器取代了小天使,想要在沒人的地方裸體,看來還是得注意點呢!

已經從顧及他人觀感到愛護自己健康,愛護自己更具有說服力,潔身自愛成為新的主流,人際之間的階層關係沒有說服力,誰能抵擋健康這一個理由呢!

什麼時候會拋棄自己的文化舉動呢?向低等人示友好厚愛時,做出一樣羞恥的事情,反而會更加地容易親近,但是相反地會更鞏固之間的階層關係 (因為認同彼此階級的差別)。

論餐桌夾菜

  • 階層社會:以示照顧、關愛
  • 平等社會:侵犯主權

被傷害的孩子

禮儀演進消耗百年,而孩子卻要在數年之內完成禮儀和羞恥的學習,這麼巨量的訊息藉由不同管道了解,每當我們認為小孩相當不禮貌時,同時也表示我們對於禮儀的要求又更高。

結語

如果在沒人的地方,做出平常人不會做的事情,就真的羞恥了嗎?為什麼沒有傷害別人,卻也必須冠上妨害風化、風俗的罪名。為了防止無知的效仿效應,難道這一點趣味都要遏止?

禮儀教給我們到底是什麼?更加鞏固自己的地位嗎?區分彼此身分的第一印象嗎?我們遵守禮儀失去了真正生物的本能,就如捷運殺人案,反抗本能消散,我們是怎麼失去暴力的。

作業

請觀看影片 2 cellos “Thunderstruck”,並從文明化的觀點分析(100字)

大人們固定成形的價值觀,相較於小孩更難以改變,只要一更動部分可能就會替換掉一大部分觀念,年輕人講出來的點子的基準不同,彼此之間的溝通性好、衝突少。才會造就影片中受到小孩喜歡、大人們卻難以接受的情況。

Read More +

[通識] 文明的進程 Week 3

上週因為上課在想題目,花了一大段時間在挑戰不可能的任務,最後宣告無法在指定要求下的時間內完成。

首先,講到十五世紀到文藝復興這段時間,歐洲開始興起的禮儀運動,儘管當時的跟現代禮儀差距是巨大的,那時人們認為的禮貌到了現代說不定還會被當作詬病。

禮貌運動從何來?為什麼突然會有禮貌之分?要求別人也要有禮貌,為了看起來合適、舒服?什麼是 羞恥 嬌貴 ?對於沒有在自然界存有的情感,人類為什麼卻擁有?

這些都源自於 階級 的出現,為了凸顯同種之間的高低之分,階級是很重要的,以人類而言,同種之間差別不太能從外表體現,就以行為舉止來作為第一印象。為什麼一開始不說外表呢?在物質還沒有這麼豐裕之前,其實貴族和平民之間差別並不大,所以追溯歷史,一開始比較注重行為舉止,往後才在物質豐饒的社會中,開始利用光鮮亮麗的裝飾品來凸顯階層。

階級仇視,每當越強調階級之差時,人民對於仇視的怨念增強,不外乎看看我們的 PTT 鄉民們,好吧,也許不是,那島民呢?

從刀槍物質上的強大區分階級,隨後已經變成了無形的距離之差反應階級,看著那騎士精神的消散,就能明白人們不再以武力來講自己有多偉大、崇高。

「我比你高貴,但不是單純的外在,而是你那難以進化的心靈。」

現代如何區分過去?我們開始追求極簡化的結構、嚴謹的環境以及情感上所呈現的一種寧靜安穩的姿態,講著講著,有點類似難以動搖的心靈,受任何波折都不容易易怒。說來笑話,這有點 面癱 了,都要變成非生物的巨石,也許擺脫生物本能變成大自然的一部分,才是真正的高貴吧!

為什麼宗教會興盛?從現代人的眼光來看,有普及教育的出現,信不信教沒有特別的意義,但為什麼還有人信?就是看著原先那些信教的人們,看起來比較崇高、端莊,加入宗教就能與它們站在相同的地位,向宗教最高的神悔過自己的罪孽,不斷地心靈規訓,就能煥然一新?

加入咱們宗教,就能升一級哦!你就會有所不同!

把持不住的孩子們都去了,人活著就耐不住寂寞、離群,「照著人多的地方走,肯定不會有問題的!」某方面的確是這樣,這沒有什麼對錯,「我思故我在」你曾是否講過做點不同的?還是一本死嗑?

禮儀書是什麼?告訴你「 如何去做 」出這種書的人自己不去做嗎?又是哪種人出了這種書?社會階層流動時,人們有機會往上爬,才會去夢、才有動力,禮儀書正是隨著洪流而出,學習與分享,只有下階層的人們才懂得那些事。

那上面的人要怎麼穩固自己的勢力呢?把原本區分階級的方式變得更加複雜,倒不如說奇特、古怪,努力地推層出新,就是為了要防止自我的存在貶值。

聽著老師說的這些,看來我要去悔過。

Read More +

計算幾何 - HW01

Chapter 1

1.1

The convex hull of a set S is defined to be the intersection of all convex sets that contain S. For the convex hull of a set of points it was indicated that the convex hull is the convex set with smallest perimeter. We want to show that these are equivalent definitions

a. Prove that the intersection of two convex sets is again convex. This implies that the intersection of a finite family of convex sets is convex as well.
b. Prove that the smallest perimeter polygon P containing a set of points P is convex.
c. Prove that any convex set containing the set of points P contains the smallest perimeter polygon P.


a. 證明兩個凸包交集仍然是凸包
假設凸包分別為 $C1, C2$,題目所求 $C = C1 \bigcap C2$
已知:A set $K$ is convex if each $u \neq v$, the line-segment $\bar{uv}$ is contained in $K$, $\bar{uv}\subseteq K$
假設 $C$ 不是凸包,則存在 $\bar{uv} \nsubseteq C$,根據定義 $u, v \in C1, C2$,得到 $\bar{uv} \nsubseteq C1, C2$,矛盾得證 $C$ 一定是凸包。

b. 證明最小周長的多邊形 P 包含所有點集 S 一定是凸包
假設 $P$ 是最小周長的非凸包多邊形,令 $x, y \in P, and \bar{xy} \nsubseteq P$,則 $\bar{xy}$ 會交 $P$ 於至少兩點 $x', y'$$P'$ 是將 $\bar{x^{'}y^{'}}$ 連起所產生的新多邊形,顯然地 $P'$ 的周長更小。矛盾得證。

c. 證明任何一個凸多邊形 C 包含點集 S 的同時也一定會包含最小周長的多邊形 P。
假設有 vertex $v \in P, but v \notin C$,同時 v 不會在 S 範圍中,因為 C 已經包含了 S。$v1, v2$$C, P$ 交點,則 $P'$$v1, v2$ 相連產生的多邊形,則 P’ 藉由 (b) 一定是多邊形,v1 到 v2 的距離更短,找到一個周長更小的多邊形。矛盾得證。

1.3

Let E be an unsorted set of n segments that are the edges of a convex polygon. Describe an O(nlogn) algorithm that computes from E a list containing all vertices of the polygon, sorted in clockwise order.


Algorithm:

  1. 得到所有點 ${(x1, y1), (x2, y2), ..., (xn, yn)}$,並且附加是屬於哪兩個邊的端點對點作排序。map< point, vector<seg> > R - O(n log n)
  2. 挑最左下的角當作 $(x1, y1)$ 的其中一邊
    1
    2
    3
    4
    5
    6
    7
    A[0] = (x0, y0) = R.begin().first;
    for (int i = 0; i < E.size(); i++) {
    for (seg s : R[A[0]]) {
    if (s.p0 == A[i] && (i == 0 || s.p1 != A[i-1]))
    A[i+1] = s.p1;
    }
    }
  3. 檢查是否為順時針,否則反轉序列 - O(n)

1.8

The O(nlogn) algorithm to compute the convex hull of a set of n points in the plane that was described in this chapter is based on the paradigm of incremental construction: add the points one by one, and update the convex hull after each addition. In this exercise we shall develop an algorithm based on another paradigm, namely divide-and-conquer.

a. Let P1 and P2 be two disjoint convex polygons with n vertices in total. Give an O(n) time algorithm that computes the convex hull of P1 ∪P2.
b. Use the algorithm from part a to develop an O(nlogn) time divide-andconquer algorithm to compute the convex hull of a set of n points in the plane.


D&C 的 O(n log n) 凸包算法

a. 將兩個沒有相交的凸包,用 O(n) 時間內合併凸包 $P1 \cup P2$

假設兩個凸包儲存方式都是逆時針順序,並第一個節點為最左下的節點。
Algorithm:

  1. 將最左側的凸包另為 P1,反之 P2。
  2. 代碼如下,找到下凸包 - O(n)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    vector C
    C[m = 0] = P1[0]
    for (i = 1, j = 0; i < P1.size(); i++) {
    if (m >= 2 && cross(C[m-1] - C[m-2], P2[j] - C[m-2]) <= 0)
    break;
    C[m++] = P1[i]
    }
    for (; j < P2.size(); j++)
    while (m >= 2 && cross(C[m-1] - C[m-2], P2[j] - C[m-2]) <= 0)
    m--;
    C[m++] = P2[j];
  3. 仿 2. 反過來作,找到上凸包 - O(n)
  4. 上下凸包合併 - O(n)

b.
Algorithm:

  1. 將所有點按照 x 做升排序 - O(n log n)
  2. 1
    2
    3
    4
    5
    6
    7
    convex DC(int l, int r, point p[]) {
    if (l == r)
    return convex(p[l])
    convex leftconvex = DC(l, (l + r)/2, p);
    convex rightconvex = DC((l+r)/2 + 1, r, p);
    return merge(leftconvex, rightconvex);
    }

Prove $T(n) = 2 T(n/2) + O(n)$,
by master theorem: $a = 2, b = 2, c = 1, log_{a}b = c, \Rightarrow T(n) = \theta (n^{c} log n) = \theta (n log n)$


Chapter 2

2.1

Let S be a set of n disjoint line segments whose upper endpoints lie on the line y=1 and whose lower endpoints lie on the line y=0. These segments partition the horizontal strip [−∞ : ∞]×[0 : 1] into n+1 regions. Give an O(nlogn) time algorithm to build a binary search tree on the segments in S such that the region containing a query point can be determined in O(logn) time. Also describe the query algorithm in detail.


參閱實作 b321: 河道分界

Algorithm: (build)

  1. sort 線段 (根據上方的 (x, 1) 進行由小排到大 ) - O(n log n)
  2. 靜態建造,動態建造請參閱可平衡的 BST。因為任切一條 y = k 的線,保證相交的 x 值得順序不會變 (跟排序結果的順序相比),因此一開始挑 y = 1 來做排序依據。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    root = dfs(0, n - 1, segments) - `O(n)`
    node dfs(int l, int r, segment segs[]) {
    if (l == r)
    return new node(segs[l]);
    else if (l < r)
    int mid = (l + r)/2;
    node ret = new node(segs[mid]);
    ret.lson = dfs(l, mid - 1, segs);
    ret.rson = dfs(mid + 1, r, segs);
    return ret;
    else
    return NULL;
    }

Algorithm: (query)

  1. 令 lbound = null, rbound = null
  2. 走訪 BST
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void query(node u, point p) {
    if u == NULL
    return;
    if p leftside by u.seg
    rbound = u
    dfs(u.lson, p)
    else
    lbound = u
    dfs(u.rson, p)
    }
  3. output (lbound, rbound)

2.5

Which of the following equalities are always true?

$$(1) Twin(Twin(\vec{e})) = \vec{e} \\ (2) Next(Prev(\vec{e})) = \vec{e} \\ (3) Twin(Prev(Twin(\vec{e}))) = Next(\vec{e}) \\ (4) IncidentFace(\vec{e}) = IncidentFace(Next(\vec{e})) \\$$

(1)(2)(4) are always true. (3) may not be true.

2.6

Give an example of a doubly-connected edge list where for an edge e the faces $IncidentFace(\vec{e})$ and $IncidentFace(Twin(\vec{e}))$ are the same.


已知 $IncidentFace(\vec{e}) = IncidentFace(Next(\vec{e}))$ always true,讓 $Next(\vec{e}) = Twin(\vec{e})$ always true。

Half-edge Orign Twin IncidentFace Next Prev
$\vec{e_{1, 2}}$ $v_{1}$ $\vec{e_{2, 1}}$ f1 $\vec{e_{2, 1}}$ $\vec{e_{2, 1}}$
$\vec{e_{2, 1}}$ $v_{2}$ $\vec{e_{1, 2}}$ f1 $\vec{e_{1, 2}}$ $\vec{e_{1, 2}}$

2.14

Let S be a set of n disjoint line segments in the plane, and let p be a point not on any of the line segments of S. We wish to determine all line segments of S that p can see, that is, all line segments of S that contain some point q so that the open segment pq doesn’t intersect any p not visible line segment of S. Give an O(nlogn) time algorithm for this problem that uses a rotating half-line with its endpoint at p.


參閱實作 b325: 人格分裂

Algorithm:

  1. 對於所有的端點相對 p 做極角排序,並且知道相對應的角度上會存有那些線段的端點。
    1
    2
    3
    4
    5
    6
    7
    map<double, vector<int, int> > angle;
    for (int i = 0; i < n; i++) {
    double v1 = atan2(D[i].s.y - pos.y, D[i].s.x - pos.x);
    double v2 = atan2(D[i].e.y - pos.y, D[i].e.x - pos.x);
    angle[v1].push_back(make_pair(i, 0));
    angle[v2].push_back(make_pair(i, 1));
    }
  2. 藉由出現的角度,使用極角掃描,一開始必須將碰的線段加入。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    double c;
    CMP::base = pos;
    double ftheta = angle.begin()->first;
    pair<int, int> u = angle.begin()->second[0];
    Pt fpt;
    if (u.second == 0)
    fpt = D[u.first].s;
    else
    fpt = D[u.first].e;
    for (int i = 0; i < n; i++) {
    if (cross(pos, fpt, D[i].s) * cross(pos, fpt, D[i].e) < 0)
    S.insert(D[i]);
    }
    CMP::sin = sin(ftheta);
    CMP::cos = cos(ftheta);
    for (map<double, vector< pair<int, int> >, CMP2>::iterator it = angle.begin();
    it != angle.end(); it++) {
    CMP::sin = sin(it->first);
    CMP::cos = cos(it->first);
    for (int i = 0; i < it->second.size(); i++) {
    pair<int, int> u = it->second[i];
    if (u.second == 0)
    c = cross(pos, D[u.first].s, D[u.first].e);
    else
    c = cross(pos, D[u.first].e, D[u.first].s);
    if (fabs(c) > eps) {
    if (c > 0)
    S.insert(D[u.first]);
    else
    S.erase(D[u.first]);
    }
    }
    if (S.size()) {
    visual[S.begin()->label] = 1;
    }
    }

心得

出題目,出題目,萌萌哒

Read More +

[通識] 文明的進程 Week 2

Front of the Class

電影《Front of the Class》(中譯:叫我第一名),是一部關於妥瑞症的一部電影。

問題

  • 男主角不想在什麼地點出現?這些地點有什麼共同特徵?

電影院、教會、音樂會、圖書館、體育場 … 等,這幾個地點都有著密集的人群,而且屬於室內環境,參與的人都有必須遵守的共同禮儀,因此無法容忍偶發性不正常的反應,這將會造成秩序上的不平衡。

  • 為什麼面試教師一直遭校方的反對?

首先,猜測幾點,先不管妥瑞症是否會對於男主角教學能力上的影響,既然捧著校方認可的同意書和成績,面試的基本門檻是過了。但是,哪個地方都不想要找一般的教師呢?一個突然會狗叫的教師將會給學校的門面帶來多少影響?是不是會有家長不讓學生進這個學校?即使校長願意讓男主在此教書,而家長的無知是否又會造成招生困難?

因此,害怕成為異類的校方,當然不想立刻收這位老師進來,不管後面的利益為何,有時候根本屬於未知的情況,因為根本沒有這種先例存在的話,只有極少數的人敢願意嘗試。

「害怕」和「不想」兩回事

  • 如果身邊有一個反應不太正常的人,你會怎麼做?

當然,妥瑞症所造成的肢體痙攣看來的確有點可怕,但是並非看起來就是鬼鬼祟祟、心術不正的長相,要恰好湊出這個組合的面貌,對於妥瑞症來說還真有點難度。反應不太正常的人其實也沒有好擔心的,高中同學也是常常在教室放屁,他自己也說忍不住,甚至有一天他特地跑到教室外面放屁,結果全部午睡的教室同學,全都被屁聲驚醒起來為他拍手叫好。

這麼三年過去,屁聲也是家常便飯了,想起來是相當特別,但誰沒有那麼一兩點特別之處呢?只是恰好沒有反應在外觀行為上!

而我,其實常常聽不懂別人說的任何一個詞,不管是中文還是英文,若沒有演講者般的口說,單純靠預測和推理得到「現在說了什麼」其實相當辛苦!有時候往往是無法預測,當沒有跟說話者很熟的時候。我姊也是因為這樣,常常把我抓去找耳科看有沒有耳朵問題,還是聽力退化,但是聽力似乎還算正常。「 聽得到,卻聽不懂 」的痛苦,一定會有人說是沒專心聽,請問「誰願意聽不清楚」,一堆人寧可聽不到一些雜語呢!

想到要跟人對談,就要有失敗的覺悟,拜託別人講第二次的勇氣越磨越光。

即使中文影片,有時還真希望有字幕 …

Read More +

[筆記] 虛擬化技術

前提概要

本課程為暑期開課,產學合作的課程。暑期上課各種虐待,反人類行為。

Day 1 虛擬機技術簡介

虛擬化不外乎就是在同一個硬體執行環境下,同時模擬出多個的執行環境,當然不外乎模擬的行為都是間接對機器硬體執行,因此許多指令需要被轉譯,或者是多好幾個步驟來做轉換,因此效率上一定會慢許多。

虛擬化的好處在於,根據硬體的汰換率在維護的費用,每隔固定一段時間就必須增加硬體來服務新的需求,如此一來必須要有更大的空間和電費來部屬伺服器。而且每一台伺服器的功率沒有一直維持高效佔有 (即使 CPU 使用率不高,用電量也不會下降多少,貌似 10% 不到,可以說是少得可憐)。倒不如來整合硬體,根據需求進行分配,同時可以讓需要的空間縮小、電費下降,做到整合到同一台機器上運行,就需要虛擬化的技術。

虛擬化技術分很多層面,最常見的就是在 Host OS 上開始虛擬化的軟體,如 VMware workstation, xen 之類的,在上面可以掛載很多不同的作業系統 Guest OS 執行。在全虛擬化的情況 (如上述),與一般使用個人電腦沒有什麼差別,所以非常容易入手。半虛擬化效率上又比全虛擬化來得高,在硬體需求上部分不使透過軟體進行,可以在高效率的情況下接軌。

在虛擬化的另一個最常見的就是 JVM,這是在 Application 面向的虛擬化,Java visual machine,提供跨平台等服務,這麼看起來虛擬化無所不在。

虛擬化有幾個困難之處,從經濟面向來看,一開始的轉移到虛擬階段和虛擬化的授權費用太高,畢竟不是所有虛擬化的技術都是 open source。從技術層面來看,虛擬化必須針對硬體做銜接,因此有時候必須靠有限的資源進行組合,才能完成虛擬化的單一功能,因此在初步階段,還必須看 Intel 等硬體架構,是否有考慮虛擬化的設計。在現今,已經有根據虛擬化進行設計,虛擬化也更為普及。

在周邊設備上,虛擬化的架構設計也相當重要,因此部份廠商也搭配他們的驅動程式 driver 進行修改和開源,來方便虛擬化的製作。

但也不是所有情況都適合虛擬化

  • 大量計算程序
  • 本身的 CPU 就一直維持滿載
  • 大量 I/O 的程序
  • 原本的執行環境沒有辦法虛擬化 (虛擬化廠商沒有針對其設備)

虛擬化還必須搭載四個主要的功能:

  • 多工
  • 狀態儲存
  • 狀態復原
  • 狀態遷徙 (無延遲服務)

虛擬化技術仍有安全疑慮,如何確保資訊安全和風險保證?

平常 VMware workstation 開啟就佔了相當記憶體資源 Orz

Day 2 軟體測試與 VM 測試

用 code coverage 來決定測試好壞,是否能逆向找到 code coverage 的測試情況。

這一天的內容已經在做專題的時候,由指導教授講了好幾次,概念上差不多能理解一大半。

重點為軟體工程的運行面向

  • debug
  • test-driven develop
  • continuous integration

正常大學不會教這些軟工概念,因此在大學畢業進入職場,挺多公司還是會給一段時間來訓練這些運行模式。來教導開發方式和其價值所在,催促人做事必須先教導其價值。

debug 技術而言,從海森堡 BUG、薛丁格 BUG … 等,都是相當有意思的。《BUG 的類型》,知道 BUG 也不見得能修好,這就是現在的情況,而有些 BUG 只會在高階 (過度) 使用者身上才會見到,軟體公司甚至不會想去修 (看看邪惡的微軟便是如此)。從 printf() 開始抓 BUG 的初學技巧,演化到加入中斷點來程序慢慢清除,用 assert() 來防止不符合規格的輸入,用 #ifdef DEBUG 使用 b2g system program 來查閱狀況,雖然不太善用這些技巧,但是 assert()#ifdef DEBUG 偶爾在無法一次掛載在腦部的時候就會採用。

很慶幸,在大學畢業前還有用過這些技巧來 DEBUG,雖然只是在單純的 ACM 解題上使用。

test-driven develop (測試驅動),這在敏捷開發這套軟工方法中談到。比起程式代碼,測試資料更令人可貴,這也是為什麼挺多大學的開發團隊會藉由參加大型比賽測試資料,來拿不容易收集到的測試資料,單純只是為了測試資料而參加比賽,當然最後主辦單位最後改階段式比賽來發送資料,以免選手罷賽拿資料。

continuout integration (連續整合),從一部分一部分的代碼中,階段式完成並且測試,確保每一步都是對的,相關的工具很多,來知道每次整合遇到了什麼問題、現在改善什麼 BUG,歷史情況是如何 … 等。

詳見敏捷開發

Day 3 工業電腦虛擬化技術簡介

這一天內容與 Day 1 類似,不過更詳細說明這門課程如何運行,不過看似就會活不下去, 3 人一組在 2 個星期後期中考、4 個星期後期末考,必須要完成的 Final project。

升大四修碩班課程果然還有點落差,問題在於資源上沒有實驗室的協助,要怎麼將實習課所需要的虛擬機器的伺服器弄出來?助教講得很輕鬆,真正有資源來完成要求的人卻很少呢。

  1. Github 使用
  2. RedMine 協助

第一點有在用,但是不專精,對我來說目前只當作是垃圾倉庫使用中。還真是慘不忍睹。

Day 4 軟體容錯 與 NCU - FTVM

  1. 虛擬容錯的處理器環境要相同,是否是相當嚴苛的條件,而這個容錯只在於軟體掛點的時候,轉移狀態給另外一台虛擬機進行程序接手,在存取空間是共用的,因是為存取空間的備份不容易完成嗎?
  2. 由於容錯功能不能與許多功能兼容,是否會造成無法長時間處於容錯狀態?
Read More +

作業系統 筆記 (2)

精簡

Page-replacement algorithm

  • FIFO Algorithm
    最先載入的 Page (即:Loading Time最小者),優先視為 Victim Page。
  • Optimal Algorithm(OPT)
    以 “將來長期不會使用的 Page Page” 視為Victim Page。
  • Least Recently Used Algorithm (LRU)
    以 “最近不常使用的 Page Page” 視為Victim Page。
    • 緣由:LRU製作成本過高
    • 作法:
      • Second econd Chance ( 二次機會法則 )
      • Enhance nhance Second Chance ( 加強式二次機會法則 )
    • 有可能退化成 FIFO FIFO,會遇到 Belady 異常情況
  • Second Chance (二次機會法則)
    以 FIFO 法則為基礎,搭配 Reference Bit 使用,參照過兩次以上的 page 將不會被置換出去,除非全部都是參照兩次以上,將會退化成 FIFO。
  • Enhance Second Chance (加強式二次機會法則)
    使用(Reference Bit Bit, Modification Bit Bit) 配對值作為挑選 Victim Page 的依據。對於沒有沒修改的 page 優先被置換,減少置換的成本。
  • Belady’s anomaly 當 Process 分配到較多的 Frame 數量,有時其 Page Fault Ratio 卻不降反升。
Rank Algorithm Suffer from Belady’s anomaly
1 Optimal no
2 LRU no
3 Second-chance yes
4 FIFO yes

Thrashing(振盪)

當 CPU 效能低時,系統會想引入更多的 process 讓 CPU 盡可能地工作。但當存有太多 process 時,大部分的工作將會花費在 page fault 造成的 Page Replacement,致使 CPU 效率下降,最後造成 CPU 的效能越來越低。

解決方法

  • [方法 1]
    降低 Multiprogramming Degree。
  • [方法 2]
    利用 Page Fault Frequency (Ratio) 控制來防止 Thrashing。
  • [方法 3]
    利用 Working Set Model “預估 ” 各 Process 在不同執行時期所需的頁框數,並依此提供足夠的頁框數,以防止 Thrashing。
    • 作法
      OS 設定一個Working Set Window (工作集視窗;Δ) 大小,以Δ 次記憶體存取中,所存取到的不同Page之集合,此一集合稱為 Working Set 。而Working Set中的Process個數,稱為 Working Set Size ( 工作集大小; WSS) 。

Page

  • Page Size 愈小
    • 缺點
      • Page fault ratio愈高
      • Page Table Size愈大
      • I/O Time (執行整個Process的I/O Time) 愈大
    • 優點
      • 內部碎裂愈小
      • Total I/O Time (單一Page的Transfer Time) 愈小
      • Locality愈集中

Fragmentation

分成外部和內部碎裂 External & Internal Fragmentation

Deadlock(死結)

  • 成因
    1. mutual exclusion 資源互斥
      一個資源只能分配給一個 process,不能同時分配給多個 process 同時使用。
    2. hold-and-wait 擁有並等待
      擁有部分請求的資源,同時等待別的 process 所擁有資源
    3. no preemption 不可搶先
      不可搶奪別的 process 已經擁有的資源
    4. circular wait 循環等待
      存有循環等待的情況

解決方法

  • Dead Lock Prevention
    不會存有死結成因四條中的任何一條。
  • Dead Lock Avoidance
    對運行的情況做模擬,找一個簡單的算法查看是否有解死結,但這算法可能會導致可解的情況,歸屬在不可解的情況。
    • Use a. to get: $ \sum Need + \sum Allocation < m + n $
    • Use c. to get: $ \sum Need_{i} + m < m + n $
    • Rewrite to get: $ \sum Need_{i} < n $
  • Dead Lock Detection & Recovery
    Recovery 成本太高

小問題

  • Propose two approaches to protect files in a file system.
    檔案系統如何保護檔案?請提供兩種方式。

    對檔案做加密動作,或者將檔案藏起-不可讀取。

  • The system will enter deadlock if you cannot find a safe sequence for
    it, YES or NO? Please draw a diagram to explain your answer.
    如果找不到一個安全序列,是否就代表系統進入死結?

    不會,因為找尋安全序列的方式通常是精心設計的通則,也就是說每個程序要求資源的方式都是可預期的運作,但實際上並不是如此,而且順序和運作都是各自獨立且不可預期,有可能途中就會釋放資源。

  • spinlock mutex semaphore 三者的區分?

    spinlock(自旋鎖)是一種佔有 CPU 效能的一種 busy waiting,而 mutex 和 semaphore 是一種根據一個資料物件來達到互斥的效果。

    就以 spinlock 來說,比較適合鎖較短的指令。相反地,mutex 和 semaphore 用於鎖住區域 (critical section) 的指令代碼。

    回過頭看 mutex 和 semaphore,mutex 只能限制單一程序進入 critical section,而 semaphore 可以自訂有多少程序可以進度 critical section,就以 binary semaphore 來說,其功能效應等同於 mutex。

Read More +

當代消費文化與社會 (3)

作文本文:

看到今年作文的題目:人只有站著世界才屬於他,這使我突然想起一個中國的近代作家的墓誌銘:我死後請將我站著埋葬,因為我活著的時候一直都跪著。

這是一個生在新中國,長在紅旗下的作家,他直到臨死的時候才發出這樣的哀鳴,可見他還是人性未泯,知道跪著的屈辱和站著的不宜。的確,半個世紀以來,中國 人中並不缺少想站著活的人,但他們無一例外成為了“杯具”,我記得其中幾個人的名字:林紹,為了站著說出真理,她被子彈打爆了纖弱的頭顱,並且,他的親人 還要再花上5毛錢來購買奪取親人生命的那顆子彈。楊佳,為了站著討要一個說法,他同樣是被子彈打碎了心臟,唯一和林紹不同的是,他的親人不需要再花錢購買 那顆子彈,這也算是一種時代的進步吧。夏俊峰,僅僅為了站著擺個養家糊口的小攤,他被注射執行了死刑,留了個全屍,感謝黨國的恩典啊!

襯托著以上想站著活著的許多“悲劇”,許多跪著活著的“喜劇”卻不斷挑逗著我們的神經:余秋雨,一個本來才氣橫溢的文化人,為了幾斗米而折腰,留下了“含 淚勸告災民書”這樣的令所有文化人蒙羞的文章。王兆山,一個高居省作協主席的所謂詩人,一首“黨疼國愛,縱做鬼也幸福”的神詩,創造了馬屁文章的又一個巔 峰。胡錫進,環球時報總編,一個堅持論證屎比肉香的報人。他們雖然拋棄了站著活的尊嚴,卻換來了榮華富貴。

今日之中國,“夢”是一個牛逼的不能再牛逼的字詞了,本來最最簡單的站著活著,怎麼就成為了中國人最遙不可及的夢想了呢?如果不是,今天的作文題目就不可 能是這樣的一個題目,在一個正常的社會,站著活著是一個再正常不過的事情了,能夠站著,這個世界上沒有人願意跪著。出題的老師想必也為此困惑,本來是教書 育人的老師,現在成了應試教育這輛戰車上的一個道具或者說是幫兇,學習的目的早已經不是學習知識造福人類這麼單純了,老師的榮譽與收入都和升學率捆綁在了 一起,為了升學率與收入,老師都跪下了,跪在了現實的利益與權力面前。但是,你們既然已經跪下了,為什麼還用這種趙構指鹿為馬的二逼遊戲來挑逗你們的學生 們呢?學生如果站著寫這篇作文,零分估計是跑不掉的,但是,跪著寫站著的讚歌,你們不覺得這樣很殘忍嗎?

我深深地知道,我今天坐在這裡來作這樣一篇作文,我所背負的責任,這是我十二年的寒窗苦讀的艱辛,這是我農民工父母縮衣節食,望子成龍的殷切期盼。這是我 的未來是在工地上搬磚頭還是坐到有空調的寫字樓裡瀟灑最關鍵的時刻。以我的文采,如果你們出一道風花雪月的文章,我劃拉幾筆就對付了,可是,既然你們出了 這樣一個嚴肅的題目,我今天就豁出去得零分大聲地對全世界說:在今天的中國,站著相比於跪著,意味著高考作文得零分,未來只有去搬磚頭。意味著活著艱難甚 至失去生命,如夏俊峰。老師如果站著教書育人,就會失去心愛的講堂,因為這樣會影響升學率。醫生如果站著救死扶傷,他就會被其他收受醫藥廠家回扣的醫生排 擠而失去醫生的工作。員警如果站著執法如山,他就會被貪贓枉法的上司“休假式治療”。在中國,站著不但不能擁有整個世界,恰恰相反,你將失去整個世界,包 括愛你的親人和朋友

也許在很久以後的未來,我們的孩子的孩子們的時代了,那時候自由之光普照大地,每一個站著的人們,或面朝大海,或面朝松濤,能夠大聲地發出沒有強權脅迫的聲音,這聲音,比擁有整個世界還令人期待,令人嚮往!!!

老師:有站著的自由,難道不比擁有整個世界更重要嗎?

此篇要點

  • 期末要繳交本課程學期心得,採以小組繳交。
  • 詳細不明,所以可以個別心得知後彙整?還是著手類似報告書的方式進行?
  • 講得再多、心得再多,通通只不過是理論、理想層面。這些對於我們的反思並沒有任何意義,充其量就是知道,然仍不會去實踐的現實,處事圓滑就是這麼回事。
  • 乃屬反社會化一派

課程收錄

第 1 週 課程簡介簡報

所有企業都是誘拐犯,

企業製造商品,開始讓我們這些生活在這個世代的人不知不覺地習慣它,不知不覺地在任何情況下被催眠去購買。在這樣的情況下,很多文化節日中,什麼節日要過什麼樣的活動、要買什麼樣的禮物早已是商人們的目標所在,很多項目早已「被消費」而我們對於發自自己的想法就越來越少,接受商人們的建議,忘了自己想要做得事情,最後就認為自己根本沒有必要去做那些事情。

「便利即是一切,大家都這麼做,為什麼要與他人相異?」

第 2 週 當代消費社會的來臨簡報

在我眼前所見,這一切都是在催眠,「正因為我們更容易見到彼此,使得我們更在乎彼此。」這一個弱點被商人們抓得死死,逐漸地商品不只有生活基礎所需,需要一個突顯自我的代號,而效果最為顯著的就是使用的物品。

一個人使用什麼商品、習慣參與或在哪一個環境,將成為一個人的特徵,如果沒有這些特徵,對於自我存在的認同就會迷失。在過往的人類中,忙碌使得他們少有時間去思考這些問題,因此將會自然地演化出他們的特徵,而在現今就不同,我們具有額外的時間來裝扮自己,但是裝扮則是由別人來決定,而我們則是選擇消費。這表示著什麼?-將不具有特徵,只是個複製。

即使包裝地再好,但我們卻沒有擁有自己。

第 3 週 消費社會學的理論介紹簡報

「認同」是行為的最終目標,消費則是在行為過程中的描述,而消費使否能體現於現實?這並不全然。如果為追求理想而產出的理念,中間歷經的辛苦算是消費嗎?我們的理念也是需要被認同的!但是這卻不算是消費行為,「努力」一詞難道就是在消費以外的存在。

我就是那麼一個異教徒,因為堅信別人不認同的理念。

炫耀性消費這的確令人討厭,這一切的價值觀全都錯亂,「擁有的確令人忌妒,沒有仍可令人輕鬆。」但是我們都是受虐狂,不斷地想要擁有,更增添了自己的憂愁。天生沒有憂愁感測器的人也是存在於世的,這與生長背景有關,通常是生活富裕或者沒有經歷過巨大挫折者。

第 4 週 商品、符號象徵與廣告簡報

對於一個人的第一印象,如果從「他/她個性很好、思考很機靈 …」到「他/她有 XXX 商品、用什麼、穿什麼 …」那明顯地,我們將開始利用商品來聯想到一個人。

廣告是企業推銷產品的唯一手法,即使是老字號的商品,雖然不用多新奇的廣告內容,但仍需要一段時間就出來宣傳一下 (通常是很長一段時間)。因為廣告效果在世代繼承方面沒有顯著的效果,在每一個世代所偏好的內容不同,因此廣告也必須跟著世代掛勾,這也是為什麼廣告層不窮地想要抓住新的世代來購買他們的商品。

廣告面相不斷地針對年輕族群,甚至對小孩下手,這些在短時間內看不出影響所在,但是長期對於價值觀培養是有一定影響,這可怕之處只有成年人才明白,新的廣告便對成年人的影響力並不高,但是只要從小還是培養 (調教) 將可以終生受用,這是一場可怕的催眠實驗。

如果人類是有智慧的生物,那小孩到底算不算人類。

第 5 週 消費者、文化資本與生活風格簡報

講到情感消費,可謂是情有獨鍾,又或者是曾經因為人生歷史事件而去接觸商品,讓人流連忘返的回憶,而標記物恰好是商品。那種浪漫的事情是多麼崇高啊!一生所追尋得就是這一類型的事情,當然指得並不是黑歷史。

一個人的品味到底有多重要?品味將會反映在生活周遭,買什麼用什麼、會交到什麼朋友 … 等,這一切會從品味著手,而也會有想要轉移目標而改變自己品味的情況,那種契機同時也是消費手段,因此企業也會嘗試將大眾的願景改變,來達到商品推銷。

第 6 週 日本 kawaii 流行文化與消費簡報李世暉

第 7 週 全球化、跨國公司與消費簡報

對課程的心得反思

以上只是部分的課堂筆記,看著其他人寫的心得,我想這應該是要寫對於這門課的心得。我選這門課的原因既不是因為學分不夠,也不是提升學期排名推研究所用途。如果事實如此,這門課就成為被消費的對象,無緣無故地,我們被學校催眠要修這些課程,學校企業也是很可怕的象徵。會有這樣的想法是在修這門課之前就有,而在修這門課又有更加地加深信心,這一切的看法只是單純來自於一個反社會化的怪人,不能大聲說出任何課程的好壞,但增加的是經驗與觀感,必須保有自己的看法,增加思考突變性,否則就只是被世間催眠的對象。

Read More +

論文選讀 Building optimal regression tree by ant colony system ...

前文

課程 計算型智慧 報告,這是一門碩班課程,因此聽了許多學長的報告,雖然有難有易,牽扯的領域相當繁雜且艱深,例如影像分析、電機、醫學領域 … 等,很多都是有聽沒有懂,但是多少能明白一些些道理,即使後來挑選幾個進行實作,發現自己根本沒有理解,或者只是單純實作能力不足。

其中最常見到的報告內容是 B*-tree with floor plan,對於電子電路的配置擺放,要求最小化面積的操作。當然其中也有幾個跟我報告的預測性有關。對於影響分析就不多述了,其中也有幾個電費電流調控也挺有意思的,總之報告內容相當多元。

報告的時候,教授就在台下緊盯,而我剛好是在教授開會的時候報告,這學期僅我一個在教授不在的情況下報告。

  • One Exam: 30%
    只有一次期中考,而且還是人腦仿電腦考試,但是題目沒有講清楚,考炸了不少,題目理解上把常數搞錯意思,但是這不影響廣義型算法,希望助教給點分!例如:在基因算法中交配的兩兩交配,難道就不能與自己交配嗎?而在粒子算法中,只給兩個參數,難道就不能只模仿全局最佳點和自己嗎?如果只有兩個參數,而且加總為一,您叫我如何模仿鄰居和自己,看來只能二選一。
  • Homework: 40% (3 programs)
  • Presentation: 30%
    教授不在的情況下仍可以報告,所以成績是由助教評定嗎?
  • Questions: 3
    本課程一定要問三個問題,否則視如無效修課,但是問題我總是在課堂中發問,對於學長報告的內容有點作噁不明白。

論文挑選為「Building optimal regression tree by ant colony system – genetic algorithm Application to modeling of melting points」這是一篇化學期刊上的運用,不是在計算機領域的論文。

開始

從一個最簡單的應用開始

在二十個問題內,能猜出心中想的目標角色。這一類的遊戲相當多,在很多遊戲或者是心理測驗中都會用到,用來預測你大概會是哪一種類型的人、或者正在想什麼。
http://en.akinator.com/

決策樹

決策樹的分類

  • Classification Tree:分類樹
    分類,輸出 “類型”
  • Regression Tree:回歸樹
    關係程度,輸出 “數值”
  • CART (Classification And Regression Tree) 即上述兩個的總稱

關於 CART

  • 大量數據可以快速算出結果
  • 易於理解 和 解釋
  • 可以用統計數據驗證模型
  • 最優 CART 是 NP 問題。
  • 能力有限,只能對有限數據屬性操作
  • 機器學習 Machine Learning 領域常用

論文實驗資料

  • 4173 種化合物,分類屬性有 202 種描述方式。在 4173 種化合物中,3000 種用來訓練,1173 種用來驗證。
  • 與另外一組經由 277 種藥物進行熔點預測的 CART 相比。(另外一篇論文做的結果)
  • 目標預測更加準確。

CART–ACS–GA 理論

  • 將 ACS – GA 算法,套用在 CART 的建造上。
  • 先說說 ACS – GA 算法運作

ACS-GA

ACS–GA 算法 (蟻群遺傳混合算法),基於 ACS 的缺點 – 收斂慢,加入 GA 算法來加快。

  • 為什麼不單純使用 GA 算法就好?
  • 對問題編碼的困難 (轉 DNA 的問題),突變效果可能不好

螞蟻基因也有好壞問題

  • 如何反應基因好壞
  • 對費洛蒙決策的方式
  • 對費洛蒙的敏感度 … 等

換句話說,將螞蟻的能力也各自數據化,對於產生較好解的螞蟻,繁殖、交配、突變,接著談論如何運用在 CART!

CART 建造

假解亂做前,如何隨機?CART 是一棵二分樹
How we do ?

  • 基於深度優先的方式,直到某個葉節點的分類種數 < 30 或深度大於某個值,就退回。
  • 每一層必須決定 “依據哪個屬性分類” Age ? Gender ? Last R ?
  • 分類時,又要按照什麼 數值 進行分割。< 30 ? > 30 ? = 30 ?

假設 CART 有 m 個節點,n 個分類描述。在此篇中,化合物有 202 種描述,即 n = 202。

  • 為了表示螞蟻的判斷能力,到達某個節點 i 時,採用下一個分類方式 k 的費洛蒙 M[i][k]
    i < m, k < n
  • 這樣可以決定分類方式。對於某個節點 i,i 可以是目前累計完成的節點個數,或者是其他。

上面決定了分類方式,但沒決定分割點 ( cut point ) 的選擇方式。

  • 假設用 10 種決策方式,來對應分類到節點內有的所有項目屬性,進行統計分類。
    • 決策方式 1:平均、眾數、權重、 ID3、C4.5 (熵理論和訊息增益) … 等分割策略
    • 決策方式 2 : 用 10 個常數對於屬性最大最小值 f(min, max) = x0 * min + x1 * max + x2 * min * max
    • 決策方式 3:最大最小值之間切 10 等分。
  • 費洛蒙將會有 10 × n × m,即 M[10][n][m]。

關於適應函數

對於葉節點

Partial least squares method 不同於 “最小平方法”

  • 多因變數 對 多自變數 的回歸建模方法
  • 對於每一個葉節點的所有資料分別做偏最小二乘法,會得到分類的相聯性,也就是 相關係數 (correlation coefficient)
  • 相關係數總和大小 與 適應力高低 成正比,用 驗證集 找到相關係數。

結論

  • 對於下次迭代,偏向於好的切割屬性
  • 對於切割屬性,可以得到好的分割點
  • 排除單一分割策略的形式
Read More +

向 NachOS 4.0 作業進發 (2)

接續

接續上一篇的 向 NachOS 4.0 作業進發 (1),我們繼續完成排程處理,在原始的 NachOS 4.0 中,基礎排程是 Round-robin,它的運作方式藉由定時呼叫 threads/alarm.h 中的 Alarm::CallBack(),而呼叫的時脈來源設定為 machine/stats.h 中的 const int TimerTicks = 100; 決定,數值越小表示呼叫頻率越高,置換的次數就會上升。

目標 Scheduler

  • FIFO (FCFS) 先來先服務
  • SJF 最短工作優先
  • Priority 最小優先權優先
  • RR (Round-robin)
  • multi-level queue 最後的大魔王

開始

第一步 - 測試

先來說說怎麼測試自己的寫的代碼正確性,不然怎麼寫都只是理論腦補,雖然會動,但是不知道是否寫對。

  • 第一種方式為下達

      $ ./nachos -e ../test/test1 -e ../test/test2 ... 多個
    

    這樣必須自己設置優先權、Burst Time,這方面撰寫方式有兩種,其一是來亂,其二是較為正式,而在 Burst Time 的計算又分成兩種,一是執行前已知、二是執行時猜測。

    • 其一來亂寫法,

        $ ./nachos -e ../test/test1 -e ../test/test2 ... 多個
      

      不改變原本的的執行方式,直接在代碼中決策 thread fork 出來時所擁有的優先權和 Burst Time。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      static int testPriority = 0;
      void
      Thread::Fork(VoidFunctionPtr func, void *arg)
      {
      // morris add
      testPriority++;
      if(testPriority == 1)
      setPriority(64);
      else if(testPriority == 2)
      setPriority(128);
      else
      setPriority(64);
      // end morris add

      因此,您可能會寫出以上的代碼,當然我不建議這麼寫,雖然是一種測試方式,但這並不好,一開始就這麼錯得相當離譜。

    • 其二寫法,增加下達參數,不過這些參數格式要去查閱一下他們的參數傳遞建造,我想會寫成大概的樣子為

        $ ./nachos -e ../test/test1 -pw 64 -e ../test/test2  -pw 128 ... 
      

      多個為了不增加工作量,這裡就沒有親自去實作。某方面來說,可能要寫很多 small program 進行測試,並且撰寫時還要預測會跑多久,這難度會稍微提高。

  • 第二種方式按照軟工的寫法
    來寫 test code 吧!如果細心一點,就會看到相關的 Class::SelfTest() 在很多 class 都有的,因此我們需要把 test code 寫到 SelfTest 中被呼叫。因此,不需要有實體的 process 運行,只是單純地測試我們寫的 scheduler 的排程順序是否正確。

    threads/thread.cc
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    void
    threadBody() {
    Thread *thread = kernel->currentThread;
    while (thread->getBurstTime() > 0) {
    thread->setBurstTime(thread->getBurstTime() - 1);
    kernel->interrupt->OneTick();
    printf("%s: remaining %d\n", kernel->currentThread->getName(), kernel->currentThread->getBurstTime());
    }
    }
    void
    Thread::SchedulingTest()
    {
    const int thread_num = 4;
    char *name[thread_num] = {"A", "B", "C", "D"};
    int thread_priority[thread_num] = {5, 1, 3, 2};
    int thread_burst[thread_num] = {3, 9, 7, 3};
    Thread *t;
    for (int i = 0; i < thread_num; i ++) {
    t = new Thread(name[i]);
    t->setPriority(thread_priority[i]);
    t->setBurstTime(thread_burst[i]);
    t->Fork((VoidFunctionPtr) threadBody, (void *)NULL);
    }
    kernel->currentThread->Yield();
    }

    請自行在 class Thread 增加 setPriority(), setBurstTime(), SchedulingTest() … 等 method header and body。
    threads/thread.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Thread {
    private:
    ...
    public:
    ...
    // morris add
    void setBurstTime(int t) {burstTime = t;}
    int getBurstTime() {return burstTime;}
    void setStartTime(int t) {startTime = t;}
    int getStartTime() {return startTime;}
    void setPriority(int t) {execPriority = t;}
    int getPriority() {return execPriority;}
    static void SchedulingTest();
    private:
    // some of the private data for this class is listed above
    // morris add
    int burstTime; // predicted burst time
    int startTime; // the start time of the thread
    int execPriority; // the execute priority of the thread
    ...
    };

    接著是需要 call testcode 加入到 ThreadedKernel 中。
    threads/kernel.cc
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void
    ThreadedKernel::SelfTest() {
    Semaphore *semaphore;
    SynchList<int> *synchList;
    LibSelfTest(); // test library routines
    currentThread->SelfTest(); // test thread switching
    Thread::SchedulingTest();
    // test semaphore operation
    semaphore = new Semaphore("test", 0);
    ...
    }

    因此我們可以利用單一 module 就能進行檢查。

          $ cd code/threads
          $ ./nachos
    

    但是這種方式,並沒有決定我們要測試哪一種類型的 scheduler,額外需要設定參數,讓其選擇建造哪一種的 readyList(Thread*)

          $ cd code/threads
          $ ./nachos FCFS
          $ ./nachos SJF
          $ ./nachos Priority
          $ ./nachos RR
    

    預計要修成如上述的測試方式。

    threads/main.cc
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    int
    main(int argc, char **argv)
    {
    ...
    debug = new Debug(debugArg);
    DEBUG(dbgThread, "Entering main");
    //
    SchedulerType type = RR;
    if(strcmp(argv[1], "FCFS") == 0) {
    type = FIFO;
    } else if (strcmp(argv[1], "SJF") == 0) {
    type = SJF;
    } else if (strcmp(argv[1], "PRIORITY") == 0) {
    type = Priority;
    } else if (strcmp(argv[1], "RR") == 0) {
    type = RR;
    }
    //
    kernel = new KernelType(argc, argv);
    kernel->Initialize(type);
    CallOnUserAbort(Cleanup); // if user hits ctl-C
    kernel->SelfTest();
    kernel->Run();
    return 0;
    }

第一步測試撰寫就這麼結束,比起撰寫新的 code,不會進行測試也是徒勞。

雖然這麼說,實際運作也是先寫 code 再寫 test code,因為當時還不太懂這些,所以如果已經先寫了一些也不用難過,大家都是這麼走過來的。

如果不知道怎麼執行,哪還有什麼撰寫的欲望,如果不知道怎麼測試,那就是在黑暗中漫步。

第二步 - 撰寫

在撰寫開始前,如果使用走第一種測試方式的人,需要將實體記憶體用大一點,否則需要實作虛擬記憶體的 context-swith。

machine/machine.h
1
2
3
const unsigned int NumPhysPages = 64; // morris modify, old value=32
const int MemorySize = (NumPhysPages * PageSize);
const int TLBSize = 4; // if there is a TLB, make it small

若完成以上的修改,在 /userprog 下,執行

1
$ ./nachos -e ../test/test1 -e ../test/test2 -e ../test/test1

就不會跑出 segment fault 。

threads/scheduler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum SchedulerType {
RR, // Round Robin
SJF,
Priority,
FIFO
};
...
class Scheduler {
public:
Scheduler();
Scheduler(SchedulerType type); // Initialize list of ready threads
...
// morris add
SchedulerType getSchedulerType() {return schedulerType;}
void setSchedulerType(SchedulerType t) {schedulerType = t;}
private:
...
};

如果有機會查閱其他代碼,很常見會把 List<Thread *> *readyList; 改成 SortedList<Thread *> *readyList; 但是其實不用的,可以利用多形來完成,畢竟 SortedList 繼承 List。因此是不需要更動的。

接著,我們使用多形,在建構子中決定要用哪一種類型的排程,並且宣告相對應的 compare function,參照如下。
threads/scheduler.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int SJFCompare(Thread *a, Thread *b) {
if(a->getBurstTime() == b->getBurstTime())
return 0;
return a->getBurstTime() > b->getBurstTime() ? 1 : -1;
}
int PriorityCompare(Thread *a, Thread *b) {
if(a->getPriority() == b->getPriority())
return 0;
return a->getPriority() > b->getPriority() ? 1 : -1;
}
int FIFOCompare(Thread *a, Thread *b) {
return 1;
}
//----------------------------------------------------------------------
// Scheduler::Scheduler
// Initialize the list of ready but not running threads.
// Initially, no ready threads.
//----------------------------------------------------------------------
Scheduler::Scheduler() {
Scheduler(RR);
}
Scheduler::Scheduler(SchedulerType type)
{
schedulerType = type;
switch(schedulerType) {
case RR:
readyList = new List<Thread *>;
break;
case SJF:
readyList = new SortedList<Thread *>(SJFCompare);
break;
case Priority:
readyList = new SortedList<Thread *>(PriorityCompare);
break;
case FIFO:
readyList = new SortedList<Thread *>(FIFOCompare);
}
toBeDestroyed = NULL;
}

上述的寫法是因為沒有辦法宣告 default argument value for class。

如果需要搶先 (Preemptive) 設計,則在 Alarm::CallBack() 決定是否要呼叫 interrupt->YieldOnReturn() 查看是否有更需要優先的 process 要執行。
threads/alarm.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void
Alarm::CallBack()
{
Interrupt *interrupt = kernel->interrupt;
MachineStatus status = interrupt->getStatus();
bool woken = _bedroom.MorningCall();
kernel->currentThread->setPriority(kernel->currentThread->getPriority() - 1);
if (status == IdleMode && !woken && _bedroom.IsEmpty()) {// is it time to quit?
if (!interrupt->AnyFutureInterrupts()) {
timer->Disable(); // turn off the timer
}
} else { // there's someone to preempt
if(kernel->scheduler->getSchedulerType() == RR ||
kernel->scheduler->getSchedulerType() == Priority ) {
// interrupt->YieldOnReturn();
cout << "=== interrupt->YieldOnReturn ===" << endl;
interrupt->YieldOnReturn();
}
}
}

在 Burst Time 計算上,如果採用運行時估計,可以在以下代碼中進行計算。kernel->stats->userTicks 是執行 user program 的時間累加器 (也存有一個 system program 的時間累加器,運行 thread context-free, thread scheduling … 等時間用途。)

threads/alarm.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
void
Alarm::WaitUntil(int x) {
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
Thread* t = kernel->currentThread;
// burst time
int worktime = kernel->stats->userTicks - t->getStartTime();
t->setBurstTime(t->getBurstTime() + worktime);
t->setStartTime(kernel->stats->userTicks);
cout << "Alarm::WaitUntil go sleep" << endl;
_bedroom.PutToBed(t, x);
kernel->interrupt->SetLevel(oldLevel);
}

其實到這裡已經完成,接下來就放幾張測試結果。

multi-programming

FCFS(1)
FCFS(2)

RR(1)
RR(2)

SJF(1)
SJF(2)

Priority(1)
Priority(1)

最後

如果在

1
2
$ cd code
$ make

編譯時發生錯誤,想必是兩個地方的 Initialize() 發生錯誤,所以請參照以下代碼進行修改。這問題是發生於我們在 /threads 下修改 main.cc 的關係,所以必須在每一個 kernel 宣告地方都給一個決定 scheduler 類型的參數。

其一,

userprog/userkernel.h
1
2
3
4
5
6
7
8
9
#include "../threads/scheduler.h"
class SynchDisk;
class UserProgKernel : public ThreadedKernel {
public:
...
void Initialize(); // initialize the kernel
void Initialize(SchedulerType type);
...

其二,
userprog/userkernel.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void
UserProgKernel::Initialize()
{
Initialize(RR);
}
void
UserProgKernel::Initialize(SchedulerType type)
{
ThreadedKernel::Initialize(type); // init multithreading
machine = new Machine(debugUserProg);
fileSystem = new FileSystem();
#ifdef FILESYS
synchDisk = new SynchDisk("New SynchDisk");
#endif // FILESYS
}

其三,
network/netkernel.h
1
2
3
4
5
6
7
8
9
10
11
#include "../threads/scheduler.h"
class PostOfficeInput;
class PostOfficeOutput;
class NetKernel : public UserProgKernel {
public:
...
void Initialize(); // initialize the kernel
void Initialize(SchedulerType);
...

其四,
network/netkernel.cc
1
2
3
4
5
6
7
8
9
10
11
12
void
NetKernel::Initialize() {
Initialize(RR);
}
void
NetKernel::Initialize(SchedulerType type)
{
UserProgKernel::Initialize(type); // init other kernel data structs
postOfficeIn = new PostOfficeInput(10);
postOfficeOut = new PostOfficeOutput(reliability, 10);
}

致網路資源

感謝網路上前人們所遺留的遺產。雖然在看不懂的文字中摸索,但仍抓到了一點線索。

我一無所有,直到見到了你們。

Read More +