Có thể giải quyết vấn đề tạm dừng nếu bạn có một đầu vào bị ràng buộc hoặc có thể dự đoán được không?


18

Vấn đề tạm dừng không thể được giải quyết trong trường hợp chung. Có thể đưa ra các quy tắc xác định hạn chế các đầu vào được phép và vấn đề tạm dừng có thể được giải quyết cho trường hợp đặc biệt đó không?

Ví dụ, có vẻ như một ngôn ngữ không cho phép các vòng lặp chẳng hạn, sẽ rất dễ dàng để biết liệu chương trình có dừng lại hay không.

Vấn đề tôi đang cố gắng giải quyết ngay bây giờ là tôi đang cố gắng tạo một trình kiểm tra kịch bản để kiểm tra tính hợp lệ của chương trình. Vấn đề tạm dừng có thể được giải quyết nếu tôi biết chính xác những gì mong đợi từ các tác giả kịch bản, có nghĩa là đầu vào rất dễ đoán. Nếu điều này không thể được giải quyết chính xác, một số kỹ thuật gần đúng tốt để giải quyết điều này là gì?

Câu trả lời:


10

Câu trả lời trực quan là nếu bạn không có các vòng lặp không giới hạn và bạn không có đệ quy và bạn không có goto, các chương trình của bạn sẽ chấm dứt. Điều này không hoàn toàn đúng, có nhiều cách khác để lén không chấm dứt, nhưng nó đủ tốt cho hầu hết các trường hợp thực tế. Tất nhiên điều ngược lại là sai, có những ngôn ngữ với các cấu trúc này không cho phép các chương trình không kết thúc, nhưng chúng sử dụng các loại hạn chế khác như hệ thống loại tinh vi.

Đệ quy

Một hạn chế phổ biến trong các ngôn ngữ kịch bản là để ngăn chặn đệ quy một cách linh hoạt: nếu A gọi B gọi C gọi các cuộc gọi A, thì trình thông dịch (hoặc trình kiểm tra, trong trường hợp của bạn) từ bỏ hoặc báo hiệu lỗi, ngay cả khi đệ quy thực sự có thể chấm dứt. Hai ví dụ cụ thể:

  • Bộ tiền xử lý C để lại một macro nguyên vẹn trong khi nó đang mở rộng macro đó. Việc sử dụng phổ biến nhất là xác định trình bao bọc xung quanh hàm:

    #define f(x) (printf("calling f(%d)\n", (x)), f(x))
    f(3);
    

    Điều này mở rộng đến

    (printf("calling f(%d)\n", (3)), f(3))
    

    Đệ quy lẫn nhau cũng được xử lý. Một hậu quả là bộ tiền xử lý C luôn chấm dứt, mặc dù có thể xây dựng các macro với độ phức tạp thời gian chạy cao.

    #define f0(x) x(x)x(x)
    #define f1(x) f0(f0(x))
    #define f2(x) f1(f1(x))
    #define f3(x) f2(f2(x))
    f3(x)
    
  • Shell Unix mở rộng bí danh theo cách đệ quy, nhưng chỉ cho đến khi chúng gặp phải một bí danh đã được mở rộng. Một lần nữa, mục đích chính là xác định bí danh cho một lệnh có cùng tên.

    alias ls='ls --color'
    alias ll='ls -l'
    

nn

Có nhiều kỹ thuật tổng quát hơn để chứng minh rằng các cuộc gọi đệ quy chấm dứt, chẳng hạn như tìm một số nguyên dương luôn giảm từ một cuộc gọi đệ quy sang cuộc gọi tiếp theo, nhưng chúng khó phát hiện hơn. Họ thường khó kiểm chứng, huống chi là suy luận.

Vòng lặp

formn

Đặc biệt, với các vòng lặp (cộng với các cấu trúc ngôn ngữ hợp lý như điều kiện), bạn có thể viết tất cả các hàm đệ quy nguyên thủy và ngược lại. Bạn có thể nhận ra các hàm đệ quy nguyên thủy theo cú pháp (nếu chúng được viết theo cách không được kiểm soát), bởi vì chúng không sử dụng vòng lặp while hoặc goto hoặc đệ quy hoặc thủ thuật khác. Các hàm đệ quy nguyên thủy được đảm bảo chấm dứt và hầu hết các tác vụ thực tế không vượt quá đệ quy nguyên thủy.


4

Xem Kẻ hủy diệtAProVe . Họ có xu hướng dựa vào heuristic, và tôi không chắc liệu họ có mô tả rõ ràng về loại chương trình mà họ làm việc không. Tuy nhiên, chúng được coi là hiện đại, vì vậy chúng nên là điểm khởi đầu tốt cho bạn.


4

Vâng, nó có thể là có thể. Một cách phổ biến để giải quyết các vấn đề như vậy là xem xét một tham số không thể tính toán thêm (đơn điệu) tùy thuộc vào mã như một phần của đầu vào. Sự phức tạp của vấn đề có tham số đó có thể được giảm đáng kể.

Chúng tôi không thể tính toán tham số, nhưng nếu bạn biết rằng các trường hợp đầu vào mà bạn đang xử lý có các giá trị tham số nhỏ, bạn có thể sửa nó thành một số nhỏ và sử dụng thuật toán.

Thủ thuật này và các thủ thuật tương tự được sử dụng trong các phương pháp chính thức để đối phó với tính không ổn định của việc tạm dừng và các vấn đề tương tự. Nhưng nếu những gì bạn muốn quyết định là phức tạp, thì độ phức tạp của các thuật toán của bạn khó có thể tốt hơn so với việc chạy thuật toán trên các trường hợp đó.

Về câu hỏi khác, nếu bạn hạn chế đủ các yếu tố đầu vào, thì vấn đề tạm dừng có thể trở nên dễ dàng. Ví dụ, nếu bạn biết rằng các đầu vào là thuật toán thời gian đa thức, việc quyết định vấn đề tạm dừng đối với chúng là không đáng kể (vì mọi thuật toán thời gian đa thức đều dừng lại).

Các vấn đề phát sinh trong các phương pháp chính thức thường không thể giải quyết được, bạn có thể muốn kiểm tra tài liệu về cách chúng xử lý các vấn đề này trong thực tế.


4

Không phải là một câu trả lời chính thức cứng nhắc, nhưng ở đây nó đi:

Vấn đề trong việc xác định nếu nó dừng lại hoặc vòng lặp mãi mãi. Vòng lặp trên các tập hợp hữu hạn một phần tử tại một thời điểm hoặc giữa một khoảng số là ok. EDIT: Rõ ràng, điều này sẽ chỉ hoạt động nếu bộ sưu tập hoặc khoảng thời gian bị cấm thay đổi (ví dụ, bởi tính bất biến) khi nó được lặp đi lặp lại (hoặc ít nhất, bị cấm phát triển).

Đệ quy có thể không ổn, trừ khi bạn đặt quy tắc nhân tạo để làm cho nó hữu hạn, như cho phép độ sâu ngăn xếp tối đa hoặc buộc tham số không âm giảm trong mỗi lần lặp.

Gotos tùy ý nói chung là xấu. Back-gotos rất có thể dẫn đến các vòng lặp có thể là vô hạn.

Các câu lệnh Whiles và do-whiles là một vấn đề, bởi vì chúng phụ thuộc vào một điều kiện không được bảo đảm để thay đổi hay không trong quá trình thực thi. Một cách có thể (nhưng có lẽ rất không thỏa mãn) để hạn chế đó là đưa ra số lần lặp tối đa có thể.


2

Bạn cần cung cấp một định nghĩa về ngôn ngữ kịch bản của bạn và ý của bạn là "mong đợi" từ những người viết kịch bản.

Ôi(nω)

Có một kết quả tương tự cho một lớp chương trình đa thức của Aaron R. Bradley, Zohar Manna và Henny B. Sipma. Nhưng AFAIK (tôi có thể sai ở đây) thời gian chạy gấp đôi theo cấp số nhân (về cơ bản là thời gian cần thiết để tính toán cơ sở Groebner).

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.