3.1. Sự khỏc nhau giữa cỏc thuật toỏn Rỳt gọn chương trỡnh
3.1.1 Rỳt gọn tĩnh (Static Slicing) và Rỳt gọn động (Dynamic Slicing)
Rỳt gọn tĩnh được tớnh khụng quan tõm đến giỏ trị đầu vào, một rỳt gọn tĩnh chứa tất cả cỏc cõu lệnh cú thể ảnh hưởng đến giỏ trị của một biến tại một điểm chương trỡnh cho tất cả cỏc lần thực thi. Với Rỳt gọn tĩnh, cỏc cõu lệnh trờn cỏc nhỏnh của cõu lệnh rẽ nhỏnh cú thể tồn tại đồng thời, điều này sẽ làm tăng kớch thước của chương trỡnh rỳt gọn.
Rỳt gọn động sử dụng thụng tin của một lần thực thi cụ thể của chương trỡnh. Trong rỳt gọn động những lần thực thi của chương trỡnh sẽ được lưu lại thành nhật kớ thực thi (Execution History) và cỏc rỳt gọn động được tớnh ra dựa trờn nhật kớ thực thi đú. Một rỳt gọn động chứa tất cả cỏc cõu lệnh ảnh hưởng thực sự đến giỏ trị của một biến chương trỡnh tại một điểm chương trỡnh cho một lần thực thi cụ thể.
Hỡnh 2.9 mụ tả sự khỏc nhau giữa rỳt gọn tĩnh và rỳt gọn động trong một vớ dụ đơn giản:
Hỡnh 2.9. Rỳt gọn tĩnh được tớnh cho cõu lệnh cuối cựng (bờn trỏi) và Rỳt gọn động cho đầu vào op = “sin” (bờn phải)
3.1.2 Rỳt gọn lựi (Backward Slicing) và Rỳt gọn tiến (Forward Slicing)
Rỳt gọn chương trỡnh được giới thiệu lần đầu tiờn bởi Weiser, bõy giờ gọi là Rỳt gọn lựi bởi vỡ chỳng chứa phần cõu lệnh phớa trờn chương trỡnh tớnh từ cõu lệnh được dựng để rỳt gọn. Ngược lại, Rỳt gọn tiến chứa phần chương trỡnh mà cõu lệnh được lấy làm rỳt gọn ảnh hưởng đến. Hỡnh 2.10 cho thấy cỏc Rỳt gọn tiến và rỳt gọn lựi cho cõu lệnh x := 3;
Hỡnh 2.10. Rỳt gọn tiến và rỳt gọn lựi
3.1.3. Rỳt gọn đơn thủ tục và Rỳt gọn đa thủ tục
Rỳt gọn đơn thủ tục là rỳt gọn trong một chương trỡnh chỉ cú một thủ tục mà trong thủ tục đú khụng cú lời gọi đến một hàm và thủ tục khỏc. Nếu chương trỡnh cú nhiều thủ tục thỡ Rỳt gọn đa thủ tục được sử dụng..
Trong rỳt gọn đa thủ tục, trong thủ tục đang rỳt gọn cú cõu lệnh gọi đến một thủ tục khỏc của chương trỡnh khi đú nội dung của thủ tục được gọi cũng phải xét đến. Cỏc thủ tục được xét đến phải theo thứ tự thời điểm thực thi. Như vậy thuật toỏn xỏc định Rỳt gọn đa thủ tục cũng tương tự như thuật toỏn đơn thủ tục song cần cú thờm một số bổ sung mới như: xử lớ lời gọi hàm, xử lớ hàm được gọi, xử lớ việc truyền tham số.
3.2 Những ứng dụng của Rỳt gọn chương trỡnh3.2.1. Bảo trỡ phần mềm (Software Maintenance) 3.2.1. Bảo trỡ phần mềm (Software Maintenance)
Bảo trỡ phần mềm là bước khụng thể thiếu trong việc tạo ra một phần mềm hoàn thiện, cụng việc đú cú thể hiểu đơn giản đú là việc hiểu phần mềm đang cú và tạo ra những sự thay đổi mà khụng làm ảnh hưởng đến những phần khụng thể thay đổi được của phần mềm. Trong phần này cú sử dụng đến một khỏi niệm rỳt gọn chương trỡnh mới đú là Rỳt gọn phõn tớch (Decomposition Slice).
Trong khi một rỳt gọn lấy giỏ trị của một biến tại điểm chương trỡnh hiện thời (cõu lệnh), còn một Rỳt gọn phõn tớch lấy tất cả tớnh toỏn của một biến và độc lập với cõu lệnh đang xét. Một Rỳt gọn phõn tớch rất tiện ớch trong bảo trỡ phần mềm, vớ dụ như một biến v nào đú được xỏc định mà giỏ trị của nú đó bị thay đổi. Trong cỏc ứng dụng sử dụng Rỳt gọn phõn tớch, việc phõn tỏch một chương trỡnh được chia làm ba phần như sau:
Phần độc lập: cỏc cõu lệnh trong Rỳt gọn phõn tớch với biến v khụng nằm trong một Rỳt gọn phõn tớch khỏc.
Phần phụ thuộc:Cỏc cõu lệnh trong Rỳt gọn phõn tớch với biến v nằm trong một Rỳt gọn phõn tớch nào đú.
Compliment: Cỏc cõu lệnh khụng độc lập (cỏc cõu lệnh trong một số Rỳt gọn phõn tớch nhưng khụng phải thuộc Rỳt gọn phõn tớch của biến v).
Cỏc biến cú thể được phần loại một cỏch tương tự như sau:
Cú thể thay đổi: tất cả cỏc cõu lệnh gỏn vào một biến là thuộc phần độc lập.
Khụng thể thay đổi: Cú ớt nhất một cõu lệnh gỏn biến nằm trong một phần phụ thuộc.
Sử dụng: Cỏc biến được sử dụng trong Compliment mà khụng thuộc phần Độc lập và Phụ thuộc.
Phần này sẽ đề cập đến một khỏi niệm đú là Kiểm thử hồi quy (Regression Testing): đú là lặp lại quỏ trỡnh kiểm thử sau một thao tỏc làm thay đổi phần mềm đú. Quỏ trỡnh này bao gồm việc chạy chương trỡnh đó sửa đổi trờn nhiều trường hợp cho dự sự thay đổi của chương trỡnh là rất nhỏ. Một số thuật toỏn dựa trờn Rỳt gọn chương trỡnh đó được đề nghị sử dụng để làm giảm chi phớ của việc Kiểm thử hồi quy. Trong khi Rỳt gọn phõn tớch sẽ rỳt ra những thành phần cần thiết cho quỏ trỡnh kiểm thử hồi quy, cú thể vẫn còn một số lần kiểm thử để chạy trờn cỏc phần Đó thay đổi, phần Phụ thuộc và phần Độc lập.
Trong thuật toỏn sau sẽ coi cỏc chương trỡnh được kiểm thử sử dụng tiờu chuõ̉n đầy đủ về dữ liệu kiểm thử, đú là: tối thiểu một bộ dữ liệu kiểm thử (một tập cỏc trường hợp dựng để kiểm thử) phải thỏa món. Một vớ dụ đú là “chuõ̉n tất cả cõu lệnh”, chuõ̉n này yờu cầu tất cả cõu lệnh trong chương trỡnh phải được thực thi bởi ớt nhất một trường hợp kiểm thử trong bộ dữ liệu kiểm thử.
Một số thuõt toỏn đó được giới thiệu với mục đớch là làm giảm giỏ thành của việc kiểm thử hồi quy cú sử dụng Rỳt gọn chương trỡnh để xỏc định cỏc thành phần ảnh hưởng giỏn tiếp bởi việc sửa tại một điểm p nào đú. Trong thuật toỏn đú người ta xét cỏc trạng thỏi của cỏc thao tỏc sửa khỏc nhau (thờm cõu lệnh, xúa cõu lệnh, sửa đổi cỏc biến sử dụng trong cõu lệnh…). Đầu tiờn, rỳt gọn là một rỳt gọn được tớnh bằng việc quay lui từ điểm p, cỏc cõu lệnh định nghĩa trong rỳt gọn (Def) đú của cỏc biến sử dụng tại điểm p được ghi lại. Rỳt gọn thứ hai là một Rỳt gọn theo chiều ngược lại cũng được bắt đầu từ p, cõu lệnh sử dụng cỏc biến được định nghĩa tại p (Use) trong Rỳt gọn này được lưu lại. Cỏc cặp Def-Use được lưu lại ở cỏc bước trờn đều bị ảnh hưởng bởi sự thay đổi nờn tất cả phải được kiểm thử lại.
Rỳt gọn chương trỡnh được khỏm phỏ giống như là một cụng cụ được tạo ra bởi cỏc lập trỡnh viờn cú nhiều kinh nghiệm khi họ tỡm và sửa lụ̃i chương trỡnh. Những người lập trỡnh, họ cú một đoạn mó cú lụ̃i ở trong đú, họ được yờu cầu là phải mụ tả đoạn mó đú sau khi đó loại bỏ lụ̃i trong đú… Cụng việc đú của họ đó đưa họ đến với khỏi niệm Rỳt gọn chương trỡnh (Program Slicing) mà chỳng ta đang tỡm hiểu.
Cú nhiều loại Rỳt gọn chương trỡnh được sử dụng trong tỡm và sửa lụ̃i (Debugging). Đầu tiờn, Rỳt gọn động (Dynamic Static) là một sự biến đổi của Rỳt gọn tĩnh được giới thiệu để hụ̃ trợ cho việc tỡm và sửa lụ̃i. Khi tỡm và sửa lụ̃i, bỡnh thường một người lập trỡnh thực hiện một lần kiểm thử lờn chương trỡnh bị lụ̃i. Một Rỳt gọn động sẽ tạo ra chương trỡnh nhỏ hơn khi thực hiện rỳt gọn tĩnh, hơn nữa rỳt gọn động còn phự hợp hơn để hụ̃ trợ cho người lập trỡnh trong việc định vị lụ̃i đặc biệt là cỏc lụ̃i là nguyờn nhõn của con trỏ và chỉ số của mảng gõy ra.
Rỳt gọn chương trỡnh cũng cú hữu ớch trong việc tỡm và sửa cỏc lụ̃i về thuật toỏn, để làm được điều đú phải dựa vào quỏ trỡnh: Bắt đầu từ một kết quả lụ̃i, thuật toỏn tỡm và sửa lụ̃i sẽ định vị lụ̃i trong một phương thức bằng việc hỏi người lập trỡnh một loạt những cõu hỏi. Những cõu hỏi đú liờn quan đến bản chất của một thủ tục, vớ dụ như: “Hàm Add(4,2) cú trả về giỏ tri 6 hay khụng?”, dựa trờn những cõu hỏi đú những phương thức cú đầu ra thỏa món sẽ được coi là làm việc tốt còn những phương thức cú đầu ra khụng thỏa món thỡ sẽ được mở ra. Điều đú cú nghĩa là cỏc trỡnh gỡ rối (Debugger) cố gắng xỏc định nếu cỏc lời gọi trong phương thức tạo ra những kết quả thỏa món thỡ sẽ khụng cần kiểm tra phương thức đú nữa và ngược lại thỡ chỳng ta sẽ sử dụng Rỳt gọn chương trỡnh để giải quyết phần còn lại của bài toỏn.
Chương 3
Cỏc thuật toỏn Rỳt gọn chương trỡnh cơ bản.
1. Rỳt gọn chương trỡnh sử dụng Đồ thị luồng điều khiển (Control Flow Graph)
Phần này trỡnh bày việc xỏc định một rỳt gọn như là kết quả của bài toỏn luồng dữ liệu sử dụng đồ thị luồng điều khiển (Control Flow Graph).
Việc tớnh một rỳt gọn từ đồ thị luồng điều khiển qua hai bước xử lớ: Đầu tiờn thụng tin luồng dữ liệu cần thiết được xỏc định. Thụng tin luồng dữ liệu là tập cỏc biến liờn quan (Relevant Set) tại mụ̃i nỳt n. Xét rỳt gọn với chuõ̉n <s,v>, tập liờn quan cho mụ̃i nỳt chứa cỏc biến mà giỏ trị của chỳng ảnh hưởng đến việc tớnh toỏn của biến v tại nỳt s.
Bước thứ hai là xỏc định cỏc cõu lệnh của rỳt gọn, chỳng bao gồm tất cả cỏc nỳt (cỏc cõu lệnh) n cú cỏc biến được định nghĩa thuộc tập cỏc biến liờn quan tại cõu lệnh s và cỏc nỳt điều khiển trực tiếp việc thực thi của nỳt chỳng.
1.1 Rỳt gọn cỏc chương trỡnh đơn giản
Cỏc chương trỡnh đơn giản là chương trỡnh chỉ cú cõu lệnh khai bỏo và cõu lệnh gỏn. Giả sử chỳng ta cần tớnh rỳt gọn theo chuõ̉n <s,v>, đối với cỏc chương trỡnh như thế thỡ tập liờn quan relevant tại mụ̃i nỳt được tớnh qua cỏc bước như sau:
i. Khởi tạo tất cả cỏc tập liờn quan bằng rụ̃ng.
ii.Thờm v vào tập liờn quan của nỳt n relevant(n).
iv.Thực hiện quay lui từ trờn xuốn dưới, lặp lại bước (iii) cho đến khi nỳt cha của m là nỳt đầu tiờn của đồ thị luồng điều khiển ninitial.
Vớ dụ 2: Hỡnh 2 cho thấy cỏc tập liờn quan cho một rỳt gọn với chuõ̉n
1.2 Rỳt gọn chương trỡnh cú cṍu trỳc
Đối với chương trỡnh đơn giản mụ̃i cõu lệnh cú duy nhất một nỳt cha, trong luồng điều khiển cú cấu trỳc một cõu lệnh cú thể cú nhiều nỳt cha. Đối với chương trỡnh cú cấu trỳc thuật toỏn rỳt gọn sẽ cú 3 thay đổi: thứ nhất là xuất hiện cỏc tập điều khiển là tập chứa cỏc cõu lệnh điều khiển, thứ hai là phải cú một quy tắc cho việc kết hợp cỏc tập liờn quan tại cỏc điểm liờn kết điều khiển, và cuối cựng là tớnh toỏn tập liờn quan cho cỏc cấu trỳc lặp. Tương ứng với những thay đổi trờn sẽ cú những giải phỏp tương ứng như sau:
Thứ nhất đú là xỏc định tập điều khiển. Tập điều khiển control(n) kết hợp với nỳt n là tập cỏc cõu lệnh điều khiển mà chỳng điều khiển trực tiếp việc thực thi của n, Đối với một chương trỡnh cú cấu trỳc, control(n) luụn chứa ninitial, cõu lệnh điều kiện (Conditional), cõu lệnh lặp (Loop) và rụ̃ng khi n là ninitial. Như vậy để xỏc định tập điều khiển tại mụ̃i cõu lệnh, kiểm tra xem cõu lệnh đú cú thuộc vựng điều khiển của cõu lệnh điều khiển nào khụng, nếu cú thỡ thờm đỉnh điều khiển đú vào tập điều khiển.
Cõu lệnh 6 thuộc vựng điều khiển của cõu lệnh 5 Control(6) = {5}
Thứ hai, xỏc định tập liờn quan tại cỏc điểm liờn kết. Tại một điểm liờn kết (ở đú cú hai nỳt cựng chung một nỳt cha) tập liờn quan được tớnh bằng hợp của cỏc tập liờn quan của cỏc nỳt lấy điểm liờn kết làm nỳt cha.
Vớ dụ 4: Xỏc định tập liờn quan tại cỏc nỳt liờn kết tương ứng với Rỳt gọn
Vớ dụ 5: Xỏc định tập liờn quan tại cỏc nỳt liờn kết tương ứng với Rỳt gọn tại <5,a>.
Thứ ba, đối với cấu trỳc lặp của chương trỡnh. Một vòng lặp trong chương trỡnh sẽ tạo ra một luồng điều khiển mà trong luồng đú cú sự lặp đi lặp lại cỏc cõu lệnh. Người ta đó tớnh được số lần duyệt cho mụ̃i vòng lặp để tớnh tập liờn quan đú là duyệt đến khi tập liờn quan của cỏc cõu lệnh ổn định, trờn thực tế người ta tớnh ra số lần duyệt bằng số cõu lệnh khai bỏo và khởi tạo trong cấu trỳc lặp.
2. Rỳt gọn chương trỡnh sử dụng Đồ thị phụ thuộc chương trỡnh (Program Dependence Graph)
2.1 Rỳt gọn chương trỡnh đơn thủ tục
PDG cho chương trỡnh P, kớ hiệu là GP là một đồ thị cú hướng, cỏc đỉnh của nú được nối bởi cỏc loại cung. Cỏc đỉnh của GP biểu diờn cỏc cõu lệnh gỏn và cõu lệnh điều khiển xuất hiện trong chương trỡnh P. GP cú đỉnh đặc biệt gọi là Entry Vertex.
GP là một đa đồ thị, tức là cú thể cú nhiều loại cung nối giữa hai đỉnh. Cỏc cung trong GP biểu diờn cỏc phụ thuộc trong cỏc thành phần của chương trỡnh. Một cung biểu diờn hoặc là phụ thuộc điều khiển (Control
Dependence) hoặc là phụ thuộc luồng (hay còn gọi là phụ thuộc dữ liệu)
(Flow Dependence). Cỏc cung phụ thuộc điều khiển được gỏn nhón là True
hoặc False và gốc của một cung phụ thuộc điều khiển luụn là một Entry Vertex hoặc một đỉnh điều khiển. Một cung phụ thuộc điều khiển từ đỉnh u đến đỉnh v kớ hiệu là ucv cú nghĩa là trong quỏ trỡnh thực thi bất cứ khi nào u được thực thi và giỏ trị của nú trựng khớp với nhón trờn cung đến v khi đú thành phần chương trỡnh được biểu diờn bởi v sẽ được thực hiện nếu chương trỡnh kết thỳc. Xét PDG GP chứa một cung phụ thuộc điều khiển từ đỉnh u đến đỉnh v của GP nếu và chỉ nếu cỏc điều kiện sau được thỏa món:
i. u là Entry Vertex và v biểu diờn một thành phần của P mà thành phần đú khụng nằm trong bất kỡ vòng lặp hoặc vựng lệnh điều kiện nào cả, cung đú được gỏn nhón True.
ii. u biểu diờn một cõu lệnh điều khiển và v biểu diờn một thành phần của P nằm trực tiếp trong vòng lặp hoặc vựng cõu lệnh điều kiện.
Nếu u là điều khiển của vòng lặp while, for khi đú cung ucv được gỏn nhón là true; nếu u là điều khiển của cõu lệnh điều kiện khi đú cung ucv
được gỏn nhón là true hay false tựy thuộc vào v xuất hiện trong nhỏnh then
hay nhỏnh else.
Cỏc cung phụ thuộc luồng của một PDG được xỏc định sử dụng cỏc phõn tớch luồng dữ liệu. Một PDG chứa một cung phụ thuộc luồng từ đỉnh u
i. u là một đỉnh mà tại đú cú định nghĩa một biến x nào đú.
ii. v là một đỉnh mà tại đú cú sử dụng biến x.
iii. Giữa hai đỉnh u và v khụng tồn tại đỉnh nào cú định nghĩa biến x.
Cỏc phụ thuộc luồng cú thể được định nghĩa cụ thể hơn bằng việc phõn loại thành loop carried và loop independent. Một phụ thuộc ufv được mang theo bởi vòng lặp L được kớ hiệu ulc(L)v nếu thỏa món (i),(ii),(iii) và cỏc điều kiện sau:
iv. Cú một đường thực thi (EP) thỏa món (iii) và cú cung quay lui lại phớa cõu lệnh điều khiển.
v. Cả hai u và v đều nằm trong vòng lặp L.
Một phụ thuộc luồng ufv là một loop independent kớ hiệu là uliv nếu thỏa món (i),(ii),(iii), cú một đường thực thi thỏa món (iii) và khụng cú cung quay lui, u và v đều nằm trong vòng lặp.
Với đỉnh s của PDG G, rỳt gọn của G tại đỉnh s kớ hiệu là Slice(G,s) là một đồ thị chứa tất cả cỏc đỉnh trờn đú s cú một phụ thuộc điều khiển hoặc phụ thuộc luồng:
Tập đỉnh:
V(Slice(G,s)) = {v V(G)|v*c,f s}.
Tập cung:
Hỡnh 3.1. Chương trỡnh và Đồ thị phụ thuộc chương trỡnh tương ứng.
2.2 Rỳt gọn chương trỡnh đa phương thức sử dụng SDG
Bài toỏn rỳt gọn cho chương trỡnh đa phương thức là một mở rộng của bài toỏn đơn thủ tục, vỡ thế nú sẽ cú một vài thay đổi trong thuật toỏn. Những thay đổi trong thuật toỏn cho chương trỡnh đa phương thức đú là phải biểu diờn: lời gọi hàm, Procedure Entry, cỏc tham số, và việc truyền tham số.