Làm thế nào để đối phó với các mảng trong các bằng chứng chính xác theo kiểu Hoare


11

Trong cuộc thảo luận xung quanh câu hỏi này , Gilles đã đề cập chính xác rằng bất kỳ bằng chứng chính xác nào về thuật toán sử dụng mảng phải chứng minh rằng không có truy cập mảng ngoài giới hạn; tùy thuộc vào mô hình thời gian chạy, điều này sẽ gây ra lỗi thời gian chạy hoặc truy cập vào các phần tử không phải là mảng.

Một kỹ thuật phổ biến để thực hiện các bằng chứng chính xác như vậy (ít nhất là trong các nghiên cứu đại học và có thể trong xác minh tự động) là sử dụng logic Hoare . Tôi không biết rằng bộ quy tắc chuẩn chứa bất kỳ thứ gì liên quan đến mảng; chúng dường như bị hạn chế với các biến đơn trị.

Tôi có thể tưởng tượng thêm các tiên đề của mẫu

{0i<A.lengthP[A[i]/E]} A[i]:=E; {P}

Tuy nhiên, nó không phải là rõ ràng với tôi làm thế nào bạn sẽ đối phó với một truy cập mảng ở phía bên tay phải, tức là nếu nó là một phần của một biểu thức phức tạp trong một số tuyên bố x : = E .Ex:=E

Làm thế nào các truy cập mảng có thể được mô hình hóa trong logic Hoare để sự vắng mặt của các truy cập không hợp lệ có thể và phải được chứng minh về tính chính xác của chương trình?

Câu trả lời có thể cho rằng chúng tôi không cho phép các phần tử mảng được sử dụng trong các câu lệnh khác ngoài A[i]:=E hoặc là một phần của một số E trong x:=E vì điều này không hạn chế tính biểu cảm; chúng ta luôn có thể gán một biến tạm thời giá trị mong muốn, tức là viết t:=A[i]; if(t>0) thay vì if(A[i]>0).

Câu trả lời:


8

Tiên đề của bạn không thực sự là một tiên đề, nó thiếu các giả thuyết. Bài thuyết trình đơn giản của Luận lý Hoare thao tác công thức có dạng nơi PP ' là công thức hợp lý và C là một lệnh. Bạn cần phải đảm bảo rằng C được hình thành tốt . Trong các ngôn ngữ đơn giản như những ngôn ngữ thường được sử dụng cho lần giới thiệu đầu tiên về logic Hoare, sự hình thành tốt là cú pháp: đó thường là vấn đề kiểm tra C{P}C{P}PPCCCphù hợp với một ngữ pháp không ngữ cảnh và có thể các biến miễn phí nằm trong một tập hợp được phép. Nếu ngôn ngữ bao gồm các cấu trúc có tính chính xác về ngữ nghĩa, chẳng hạn như truy cập vào các phần tử mảng, bạn cần thêm các giả thuyết để diễn tả tính chính xác ngữ nghĩa này.

Chính thức, bạn có thể thêm các phán đoán để diễn tả sự điều chỉnh biểu thức và lệnh. Nếu các biểu thức không có tác dụng phụ, chúng không cần hậu điều kiện, chỉ có điều kiện tiên quyết. Ví dụ: bạn có thể viết các quy tắc định dạng tốt, chẳng hạn như

{P}E wf{P0E<length(A)}A[E] wf{P}E1 wf{P}E2 wf{P}E1+E2 wf
{P[xE]}E wf{P[xE]}x:=E{P}

errorerrorError¬Error

{P[xE]}x:=E{PError}P[xE]Eerror{P[xE]}x:=E{P}

Tuy nhiên, một cách tiếp cận khác là xem xét bộ ba Hoare chỉ giữ nếu chương trình kết thúc chính xác. Đây là cách tiếp cận thông thường cho các chương trình sắp hết hạn: postcondition giữ khi lệnh kết thúc, điều này có thể không luôn luôn xảy ra. Nếu bạn coi các lỗi thời gian chạy là không chấm dứt, bạn sẽ quét tất cả các vấn đề chính xác dưới mui xe. Bạn vẫn sẽ cần phải chứng minh tính đúng đắn của chương trình bằng cách nào đó, nhưng nó không cần phải theo logic Hoare nếu bạn thích một số hình thức khác cho nhiệm vụ đó.

Nhân tiện, lưu ý rằng việc diễn tả những gì xảy ra khi một biến tổng hợp như một mảng được sửa đổi có liên quan nhiều hơn đến những gì bạn đã viết. Giả sử là, nói, : sự thay thế sẽ không thay đổi , tuy nhiên sự phân có thể làm mất hiệu lực . Ngay cả khi bạn hạn chế cú pháp của các vị từ chỉ nói về các nguyên tử, hãy xem xét phép gán theo điều kiện tiên quyết : bạn không thể thực hiện một sự thay thế đơn giản để có được kết quả chính xác , bạn cần đánh giáPIsSorted(A)A[i]EPA[i]PPA[A[0]1]:=A[0]A[0]=2A[1]=3A [ 0 ] A [ 0 ] A A [ i E ]A[0]=1A[1]=1A[0](nói chung có thể khó khăn, vì điều kiện tiên quyết có thể không chỉ định một giá trị khả dĩ duy nhất cho ). Bạn cần thực hiện thay thế trên chính mảng: . Ghi chú bài giảng của Mike Gordon có phần trình bày logic Hoare tốt với các mảng (nhưng không kiểm tra lỗi).A[0]AA[iE]


0

Như Gilles đã đề cập, có một tiên đề gán mảng (xem ghi chú của Gordon, Phần 2.1.10 ): Trong các từ, nếu bạn có một phép gán mảng, thì thay thế mảng ban đầu bằng mảng có vị trí giá trị . Lưu ý rằng nếu bạn đã có trên bài đăng và gán , thì bạn nên lấy làm tiền tố (vâng, theo thứ tự này - cập nhật gần đây được thực hiện trước!).

{Q[AA.store(i,expr)]}A[i]=expr{Q}
A.store(i,expr)iexprA.store(i,vi)A[j]=vjA.store(j,vj).store(i,vi)

Ngoài ra, chúng tôi cần tiên đề truy cập mảng: A.store(i,v)[i]có thể được thay thế bằng v("nếu bạn truy cập phần tử thứ mà bạn vừa cập nhật, sau đó trả về giá trị được gán").i

Tôi nghĩ rằng để chứng minh một chương trình với các mảng là chính xác ("không có quyền truy cập ngoài giới hạn"), các tiên đề trên là đủ. Hãy xem xét chương trình:

...
A[i] = 12
...

Chúng tôi sẽ chú thích chương trình này:

...
@ {0<i<A_length}
A[i] = 12
...

trong đó A_lengthmột biến chỉ định chiều dài mảng. Bây giờ hãy cố gắng chứng minh chú thích - cụ thể là làm việc ngược lại (từ dưới lên trên, "như thường lệ" trong bằng chứng Hoare). Nếu trên đầu bạn nhận được {false}, thì việc truy cập ngoài ràng buộc có thể xảy ra, nếu không, biểu thức bạn nhận được là điều kiện tiên quyết mà theo đó không có quyền truy cập ngoài giới hạn nào có thể xảy ra. (ngoài ra, chúng ta cần đảm bảo rằng khi mảng được tạo như thế int A=int[10];thì trong điều kiện hậu chúng ta có {A_length==10}).


Tiên đề của bạn không mô hình truy cập ngoài giới hạn: họ thậm chí không đề cập đến chiều dài! Trong chương trình ví dụ của bạn, làm thế nào để bạn liên quan lengthđến A?
Gilles 'SO- ngừng trở nên xấu xa'

Phải, các tiên đề không mô hình ra khỏi truy cập ràng buộc. Đầu tiên, để chứng minh một chương trình là chính xác, tôi thêm các chú thích yêu cầu quyền truy cập nằm trong giới hạn. ( lengthđã được đổi tên A_length.) Thứ hai, chúng ta cần các tiên đề "tạo" mảng như thế nào int[] a = int[length] {a_length==length}. Tôi nghĩ rằng điều này là đủ.
Ayrat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.