Làm thế nào bạn có thể xây dựng một bảng ghi nhớ cưỡng chế cho các hàm đệ quy trên cây nhị phân?


8

Các StreamMemo thư viện cho Coq minh họa cách memoize một chức năng f : nat -> Aso với các số tự nhiên. Đặc biệt khi f (S n) = g (f n), các imemo_makechia sẻ tính toán của các cuộc gọi đệ quy.

Giả sử thay vì số tự nhiên, chúng tôi muốn ghi nhớ các hàm đệ quy trên cây nhị phân:

Inductive binTree : Set := | Leaf : binTree | Branch : binTree -> binTree -> binTree.

Giả sử chúng ta có một hàm f : binTree -> Ađệ quy có cấu trúc, nghĩa là có một hàm g : A -> A -> Anhư vậy f (Branch x y) = g (f x) (f y). Làm thế nào để chúng tôi xây dựng một bảng ghi nhớ tương tự ftrong Coq sao cho các tính toán đệ quy được chia sẻ?

Trong Haskell, không quá khó để xây dựng một bảng ghi nhớ như vậy ( ví dụ như xem MemTrie ) và thắt nút. Rõ ràng bảng ghi nhớ như vậy là hiệu quả. Làm thế nào chúng ta có thể sắp xếp mọi thứ để thuyết phục một ngôn ngữ gõ phụ thuộc để chấp nhận việc thắt nút như vậy là hiệu quả?

Mặc dù tôi đã chỉ định vấn đề trong Coq, tôi cũng rất vui khi có câu trả lời bằng Agda hoặc bất kỳ ngôn ngữ phụ thuộc nào khác.

Câu trả lời:


4

Thật dễ dàng để có được mẫu đệ quy hoạt động với các loại có kích thước. Hy vọng việc chia sẻ được bảo tồn thông qua việc biên soạn! [1]

module _ where

open import Size
open import Data.Nat

data BT (i : Size) : Set where
  Leaf : BT i
  Branch : ∀ {j : Size< i} → BT j → BT j → BT i

record Memo (A : Set) (i : Size) : Set where
  coinductive
  field
    leaf : A
    branch : ∀ {j : Size< i} → Memo (Memo A j) j

open Memo

trie : ∀ {i} {A} → (BT i → A) → Memo A i
trie f .leaf = f Leaf
trie f .branch = trie (\ l → trie \ r → f (Branch l r))

untrie : ∀ {i A} → Memo A i → BT i → A
untrie m Leaf         = m .leaf
untrie m (Branch l r) = untrie (untrie (m .branch) l) r

memo : ∀ {i A} → (BT i → A) → BT i → A
memo f = untrie (trie f)

memoFix : ∀ {A : Set} → A → (A → A → A) → ∀ {i} → BT i → A
memoFix {A} lf br = go
 where
  go h : ∀ {i} → BT i → A
  go = memo h
  h Leaf = lf
  h (Branch l r) = br (go l) (go r)

[1] https://github.com/agda/agda/issues/2918


Cám ơn vì cái này. Tôi có hai lo lắng về mã này. Đầu tiên gogiá trị là một hàm của tham số Size. Nói chung, không có chia sẻ giữa các lệnh gọi hàm độc lập ở cùng một giá trị. Điều này có thể được khắc phục bằng cách thêm một câu lệnh let trong định nghĩa của h (Branch l r). Thứ hai, định nghĩa phân tầng BTcó nghĩa là hai cây, nếu không có hình dạng giống hệt nhau, sẽ có các giá trị khác nhau khi chúng xảy ra ở các cấp độ khác nhau. Những giá trị riêng biệt này sẽ không được chia sẻ trong Bản ghi nhớ.
Russell O'Connor

Tôi ấn tượng rằng Agda chấp nhận định nghĩa lồng Memotrong branch. Trình kiểm tra tính tích cực của Coq dường như bác bỏ điều này, khiến mọi thứ trở nên phức tạp hơn trong Coq.
Russell O'Connor

Vấn đề tôi liên kết dường như kết luận rằng kích thước không phải là vấn đề khi chạy khi được biên dịch với phụ trợ GHC, mặc dù tôi chưa tự mình xác minh điều này.
Saizan

Tôi hiểu rồi. Tôi đang tìm kiếm một giải pháp ghi nhớ có thể được sử dụng trong trợ lý chứng minh để nó có thể được sử dụng như một phần của bằng chứng bằng phản xạ. Giải pháp của bạn có lẽ phù hợp để biên dịch giả sử các Sizeloại cuối cùng bị xóa.
Russell O'Connor

0

Tôi đã tạo ra một "giải pháp" ghi nhớ đệ quy các hàm đệ quy có cấu trúc của cây nhị phân trong Coq. Ý chính của tôi là tại https://gist.github.com/roconnor/286d0f21af36c2e97e74338f10a4315b .

Nó hoạt động tương tự như giải pháp của Saizan , bằng cách phân tầng cây nhị phân dựa trên số liệu kích thước, trong trường hợp của tôi, đếm số nút bên trong của cây nhị phân và tạo ra một luồng chứa tất cả các giải pháp cho một kích thước cụ thể. Chia sẻ xảy ra do một câu lệnh let trong trình tạo luồng chứa phần đầu tiên của luồng được sử dụng trong các phần sau của luồng.

Các ví dụ cho thấy, để vm_computeđánh giá một cây nhị phân hoàn hảo với 8 cấp độ sau khi đã đánh giá một cây nhị phân hoàn hảo với 9 cấp độ nhanh hơn nhiều so với việc chỉ đánh giá một cây nhị phân hoàn hảo với 8 cấp độ.

Tuy nhiên, tôi ngần ngại chấp nhận câu trả lời này bởi vì chi phí chung của giải pháp cụ thể này rất tệ khi nó hoạt động kém hơn nhiều so với khả năng ghi nhớ của tôi mà không có đệ quy cấu trúc cho các ví dụ về đầu vào thực tế của tôi. Đương nhiên, tôi muốn một giải pháp hoạt động tốt hơn dưới các đầu vào hợp lý.

Tôi có một số nhận xét thêm tại " [Câu lạc bộ Coq] Làm thế nào bạn có thể xây dựng bảng ghi nhớ cưỡng chế cho các hàm đệ quy trên cây nhị phân? ".

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.