Bài toán tìm đường đi ngắn nhất được phát biểu như sau: ta cần tìm đường đi ngắn nhất từ một đỉnh nguồn (source) tới tất cả các đỉnh trong một đồ thị có trọng số và có hướng.
Giả sử weight(u,v) biểu diễn độ dài của cạnh nối hai đỉnh u và v, nếu không tồn tại cạnh này trên
đồ thị thì weight(u,v) =∞.
Từ năm 1959, Moore đã đề xuất một thuật toán tuần tự để giải bài toán trên. Trong thuật toán này,
hàm distance(v) được gán giá trị khởi tạo là ∞ đối với mọi đỉnh v V – {s}. Khoảng cách từ s
tới s bằng 0. Một hàng đợi chứa các đỉnh đã được duyệt, ban đầu hàng đợi chỉ chứa một đỉnh
nguồn s. Trong khi hàng đợi chưa bị rỗng, đỉnh u từ đầu hàng đợi bị loại bỏ, và tất cả các cạnh
(u,v) E sẽ được thử. Nếu distance(u) + weight(u,v) <distance(v) thì một đường đi mới tới v (qua u) được tìm thấy. Trong trường hợp này, distance(v) được đặt lại bằng distance(u) + weight(u,v) và v được đặt vào cuối hàng đợi. Thuật toán tiếp tục tiến trình này cho đến khi hàng
Hình 2.34. Minh họa thuật toán Moore.
Thủ tục INITIALIZE, được gọi ở dòng thứ 3 khởi tạo khoảng cách tới tất cả các đỉnh (không kể đỉnh nguồn s) là ∞, và khoảng cách từ s đến s bằng 0. Vòng lặp for từ dòng 12 đến 20 tìm kiếm đường đi ngắn nhất đến các đỉnh khác có thể đến được từ u.
SHORTEST PATH
Parameter n {số đỉnh của đồ thị}
Global distance {phần tử i chứa khoảng cách từ s đến i} s {đỉnh nguồn}
weight {chứa trọng số của mỗi cạnh}
1 Begin
2 For i=1 to n do 3 INITIALIZE(i) 4 Endfor
5 Chèn s vào cuối hàng đợi
6 While hàng đợi không rỗng do
7 SEARCH() 8 Endwhile 9 End
SEARCH()
Local newdistance {khoảng cách tới v nếu đường đi từ u đến v ngắn nhất} u {đỉnh u}
v {đỉnh v}
10 Begin
11 Loại đỉnh u từ đầu hàng đợi
12 For mỗi cạnh (u,v) trong đồ thị do
13 newdistance = distance(u) + weight(u,v) 14 If newdistance<distance(v) then
15 distance(v) = newdistance 16 If v không có trong hàng đợi then
17 đặt v vào cuối hàng đợi
18 Endif 19 Endif 20 Endfor 21 End
Phiên bản tuần tự của thuật toán Moore tìm đường đi ngắn nhất trên đồ thị
Làm thế nào để song song hóa giải thuật trên. Có hai cách thức cần xem xét. Cách thứ nhất là song song hóa vòng lặp từ dòng 12 đến dòng 20. Mỗi đỉnh u có một số cạnh đi ra từ đỉnh đó (đồ
thị đang xét là có hướng) ta có thể xử lý song song để tìm đường đi ngắn nhất qua u. Cách thứ hai
là song song hóa vòng lặp while từ dòng 6 đến dòng 8. Tại bất kỳ thời điểm nào khi thuật toán
thực hiện , có thể có nhiều đỉnh trong hàng đợi. Có thể có nhiều cạnh được duyệt đồng thời. Vậy
cách song song hóa nào tốt hơn. Có hai lý do ta có thể nghiên về cách thứ 2. Đó là, cách thứ 2 có
thể đạt được hiệu suất và tốc độ song song tốt hơn và cách thứ nhất bị giới hạn bởi số cạnh của
mỗi đỉnh. Nếu đồ thị quá thưa (ít cạnh trên mỗi đỉnh) số tiến trình được thực hiện song song sẽ ít.
Thuật toán song song sau đây dưa trên cách thức thứ 2. Hàng đợi được khởi tạo với một đỉnh
nguồn, thì một số tiến trình không đồng bộ sẽ được tạo ra. Mỗi tiến trình này hoàn thành một số bước loại bỏ một đỉnh trong hàng đợi, thử các cạnh ra từ đỉnh và chèn các đỉnh với đường đi
ngắn hơn vào hàng đợi.
Vòng lặp for từ dòng 2 đến dòng 4 của thuật toán tuần tự dễ dàng biến đổi để xử lý song song sử
dụng cách thức tiền lập lịch (pre-scheduling). Xử lý song song vòng lặp for từ dòng 2 đến dòng 6
được trình bày ở hình 12-8. Vòng lặp while từ dòng 6 đến dòng 8 của thuật toán tuần tự phải được thay đổi để thể hiện sự tồn tại của các tiến trình không đồng bộ thực hiện thủ tục SEARCH
một cách song song. Rõ ràng là nó không phù hợp cho một tiến trình để dừng khi nó phát hiện ra
rằng hàng đợi đã rỗng (tại sao lại như vậy: vì các tiến trình được thực hiện một cách độc lập và
đồng thời). Do vậy, một phương pháp phức tạp hơn phải được sử dụng. Trong thuật toán song
song sẽ có hai biến được sử dụng cùng nhau để xác định có hay không có việc phải làm. Biến thứ
nhất là waiting, là một mảng để theo dõi các tiến trình đang đợi. Biến thứ hai kiểu Boolean halt,
halt = true khi tất cả các tiến trình đang chờ.
Không có tranh chấp giữa các tiến trình nếu mỗi tiến trình được bảo trì một danh sách riêng các
mỗi tiến trình tự quản lý danh sách riêng của nó có thể gây ra mất cân bằng tải đối với khối lượng công việc.
SHORTEST PATH (MULTIPROCESSOR) Parameter n {số đỉnh trên đồ thị}
p {số tiến trình}
Global distance {distance (i) chứa khoảng cách từ s đến i}
halt {= true, nếu các tiến trình dừng} s {đỉnh nguồn}
weight {trọng số của mỗi cạnh}
1 Begin
2 For all Pi where 1 ≤ i ≤ p do
3 For j=i to n step p do 4 INITIALIZE(j) 5 Endfor
6 Endfor
7 Đặt s vào hàng đợi
8 halt = false
9 For all Pi where 1 ≤ i ≤ p do
10 Repeat SEARCH(i) until halt 11 Endfor
12 End
SEARCH(i);
value i {số tiến trình}
local newdistance {khoảng cách tới v} u {đỉnh u} v {đỉnh v} 1 Begin 2 Khóa hàng đợi 3 If hàng đợi rỗng then 4 waiting(i) = true 5 If i=1 then
6 halt =waiting(2) AND waiting(2) AND…. waiting(p) 7 Endif
8 Mở khóa hàng đợi
9 Else
10 lấy u ra khỏi hàng đợi
11 waiting(i) = false 12 Mở khóa hàng đợi
13 For mỗi cạnh (u,v) trong đồ thị do
14 newdistance=distance(u)+weight(u,v) 15 Lock(distance(v))
16 If newdistance < distance (v) then 17 Distance(v) = newdistance
18 Unlock(distance(v))
19 If v không có trong hàng đợi then
20 Khóa hàng đợi
21 If v không có trong hàng đợi then
22 Lấy v ra khỏi hàng đợi
23 Endif 24 Mở khóa hàng đợi 25 Endif 26 Else Unlock(distance(v)) 27 Endif 28 Endfor 29 Endif 30 End.
Thuật toán song song tìm đường đi ngắn nhất trên máy tính UMA đa bộ xử
lý
Mảng liên kết là cấu trúc dữ liệu cho phép liên kết các danh sách có kích thước khác nhau sao cho
việc chèn và tìm kiếm các phần tử trong danh sách có thể được thực hiện song song mà không có
xung đột. Giả sử rằng trong một vòng lặp đơn không có bộ vi xử lý thực hiện thao tác chèn nhiều hơn w phần tử. Trong mảng liên kết, trong trường hợp đó chứa p(w+p) phần tử, w+p phần tử trên một tiến trình. Trong một nhóm liên tiếp nhau w+p vị trí, một tiến trình có thể chứa tên các phần
tử được tìm kiếm trong vòng lặp tiếp theo. Nếu bộ vi xử lý i, 1 ≤ i ≤ p, sinh ra tên của ei phần tử được xem xét trong vòng lặp tiếp theo, thì các vị trí (i-1)(w+p) +1 đến (i-1)(w+p) + ei +p chứa
các giá trị -i (w + p +1) lần lượt giảm tới – ( i(w+p) + p)).
Trong vòng lặp kế tiếp, khi các phần tử với các tên trong mảng liên kết được thử, bộ xử lý i (1 ≤ i ≤ p) sẽ thử mỗi vị trí thứ p, bắt đầu với vị trí thứ i. Nếu giá trị gặp phải lớn hơn zero, đó là đỉnh
cần tìm kiếm. Nếu giá trị nhỏ hơn zero, đó là một con trỏ, và bộ xử lý sẽ nhảy đến chỉ số đã được
chỉ ra. Khi con trỏ có giá trị ít hơn –p(w+p), việc tìm kiếm sẽ dừng,
Thủ tục EXAMINE sau đây minh họa một tiến trình loại bỏ các phần tử chia sẻ từ một mảng
chứa các chỉ số đỉnh và các con trỏ.
EXAMINE (a,i,p,w)
Value a[1..p(w+p)], {mảng chứa số hiệu đỉnh và con trỏ}
i, {số hiệu tiến trình} p, {số các tiến trình}
w, {kích thước mảng con gắn với mỗi tiến trình}
Local j {chỉ số của mảng a}
1 Begin
2 j=i
3 While j ≤ p * (w+p) do
4 If a[j] < 0 then
5 j = -a[j] {con trỏ kế tiếp}
7 Thao tác với đỉnh có giá trị a[j]
8 j = j+p 9 Endif 10 Endwhile 11 End
Không gian lưu trữ mảng liên kết có thể rất lớn. Trừ khi nó có thể được bảo đảm không phải tất
cả các thao tác chèn có thể được thực hiện bằng một bộ xử lý đơn, thì không gian dành cho mảng
liên kết phải xấp xỉ p lần không gian lưu trữ một mảng thông thường. Phiên bản dữ liệu song
song của thuật toán Moore có thể được sửa đổi để sử dụng mảng liên kết. Trong một vòng lặp đơn, mỗi tiến trình có một số đỉnh để thử. Mỗi tiến trình xử lý danh sách các đỉnh riêng của nó để
tìm đường đi ngắn hơn và xây dựng các liên kết tới danh sách của tiến trình kế tiếp. Trong vòng lặp kế tiếp thì những danh sách này được xử lý song song. Có hai mảng được sử dụng. Trong bất
kỳ lần lặp nào luôn có một mảng được đọc trong khi mảng kia được ghi. Lần lặp kế tiếp thì vai trò của hai mảng được hoán đổi.
Hình 2.35. Nếu không sử dụng khóa hàng đợi thì hai tiến trình cùng cập nhật giá trị distance(v) sẽ
gây ra lỗi.