Apakah masalah "kehadiran pesta" dapat dipecahkan dalam Prolog? Sebagai contoh:
Burdock Muldoon dan Carlotta Pinkstone berkata bahwa mereka akan datang jika Albus Dumbledore datang. Albus Dumbledore dan Daisy Dodderidge keduanya mengatakan mereka akan datang jika Carlotta Pinkstone datang. Albus Dumbledore, Burdock Muldoon, dan Carlotta Pinkstone semua mengatakan mereka akan datang jika Elfrida Clagg datang. Carlotta Pinkstone dan Daisy Dodderidge mengatakan bahwa mereka akan datang jika Falco Aesalon datang. Burdock Muldoon, Elfrida Clagg, dan Falco Aesalon semuanya mengatakan mereka akan datang jika Carlotta Pinkstone dan Daisy Dodderidge keduanya datang. Daisy Dodderidge mengatakan dia akan datang jika Albus Dumbledore dan Burdock Muldoon keduanya datang. Siapa yang perlu dibujuk untuk menghadiri pesta untuk memastikan bahwa semua undangannya hadir?
Saya telah mencoba untuk mengekspresikan ini dalam GNU Prolog:
attend(BM) :- attend(AD).
attend(CP) :- attend(AD).
attend(AD) :- attend(CP).
attend(DD) :- attend(CP).
attend(AD) :- attend(EC).
attend(BM) :- attend(EC).
attend(CP) :- attend(EC).
attend(CP) :- attend(FA).
attend(DD) :- attend(FA).
attend(BM) :- attend(CP),attend(DD).
attend(EC) :- attend(CP),attend(DD).
attend(FA) :- attend(CP),attend(DD).
attend(DD) :- attend(AD),attend(BM).
attend(FA). /* try different seed invitees in order to see if all would attend*/
/* input:
write('invited:'),nl,
attend(X),write(X),nl,
fail.*/
Saya mengalami stack overflow (tanpa permainan kata-kata), dan tidak memiliki pengetahuan tentang evaluasi prolog, inilah mengapa saya bertanya.
Secara umum, masalah ini dapat dimasukkan ke dalam formula kepuasan Boolean CNF (dengan 6 variabel boolean). Oleh karena itu, apakah perspektif prolog pantas?
sumber
attend(BM) :- attend(AD).
persis sama denganattend(X) :- attend(Y).
Jawaban:
Untuk memecahkan masalah dengan Prolog, seperti halnya bahasa pemrograman apa pun, baik itu deklaratif atau imperatif, Anda harus memikirkan representasi solusi dan input.
Karena ini adalah pertanyaan pemrograman, itu akan populer di StackOverflow.com di mana programmer memecahkan masalah pemrograman. Di sini saya berusaha menjadi lebih ilmiah.
Untuk memecahkan masalah dalam OP, seseorang harus membalikkan hubungan yang ditentukan oleh dependensi yang dinyatakan dalam input. Klausul bentuk mudah untuk membalikkan. Klausul Sebuah t t e n d ( A D ) ∧ A t t e n d (A t t e nd( X) → A t t e n d( Y) ∧ A t t e n d( Z) sepertiA t t e n d( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
lebih sulit diobati.
Dengan Prolog pendekatan sederhana pertama adalah untuk menghindari pembalikan penuh dari hubungan dan diarahkan sebagai tujuan.
Asumsikan pemesanan pada daftar tamu dan gunakan aturan
(Kami menggunakan alih-alih A t t e n d ( X ) untuk membuatnya singkat)A ( X) A t t e n d( X)
Aturan ini mudah diterapkan.
Pendekatan yang agak naif
Untuk keterbacaan, biarkan
follows
hubungan diberikan sebagai input, danbrings
kebalikannya.Kemudian input diberikan oleh
Dan
brings
dapat didefinisikan sebagai berikut:brings/3(X,L,S)
Jika kita mendefinisikan
Kami mendapatkan solusi unik berikut:
Ini bukan daftar lengkap, karena menurut abjad memesan klausa
tidak bekerja.
Solusi yang agak terlibat untuk teka-teki asli
Untuk menyelesaikan masalah sepenuhnya Anda harus benar-benar membiarkan sistem mencoba membuktikan kehadiran untuk tamu kemudian tanpa memperkenalkan loop tak terbatas ke pohon pencarian. Ada banyak cara untuk mencapai tujuan ini. Masing masing punya kelebihan dan kekurangan.
Salah satu caranya adalah mendefinisikan ulang
brings/2
sebagai berikut:Argumen terakhir
brings/4
diperlukan untuk menghindari infinite loop intry_bring
.Ini memberikan jawaban berikut: Albus, Carlotta, Elfrida dan Falco. Namun solusi ini bukan yang paling efisien karena backtracking diperkenalkan di mana kadang-kadang dapat dihindari.
Solusi umum
Sekarang jika misalnya dataset # 2 diberikan sebagai
Kami mendapatkan jawaban L = [[iklan, bm, dd, ec]]. Yang berarti semua tamu kecuali Carlotte dan Falco harus diundang.
Jawaban solusi ini memberi saya cocok dengan solusi yang diberikan dalam artikel Penyihir Jahat dengan pengecualian dataset # 6, di mana lebih banyak solusi dihasilkan. Ini tampaknya menjadi solusi yang tepat.
Akhirnya, saya harus menyebutkan perpustakaan Prolog CLP (FD) yang sangat cocok untuk masalah seperti ini.
sumber
Seperti yang terlihat oleh svick, masalah pertama dengan kode dalam OP adalah bahwa nama yang diawali dengan huruf besar adalah variabel dalam Prolog. Begitu
admit(CP) :- admit(AD)
juga denganattend(X) :- attend(Y)
, yang menghasilkan Prolog segera memasuki infinite loop mencoba menunjukkan yangattend
berlaku untuk beberapa istilah dengan menemukan beberapa istilah yangattend
berlaku.Namun, jika Anda bermaksud bahwa setiap set inisial menjadi istilah berbeda yang nyata, maka Anda masih akan mengalami stack overflow karena Anda memiliki siklus, mis.
Jadi untuk mengetahui apakah
attend(cp)
Hold Prolog akan mencoba menentukan apakahattend(ad)
Hold, yang akan dilakukan dengan memeriksa apakahattend(cp)
Hold, dan seterusnya sampai stack overflow.Saya tidak percaya vanilla Prolog melakukan upaya untuk menentukan apakah ada siklus seperti itu, dan memeriksa cara - cara lain untuk membuat salah satu
attend(cp)
atauattend(ad)
benar daripada terjebak dalam loop yang tak terbatas.Mungkin ada atau tidak ada versi Prolog yang mendukung fitur tersebut. Saya lebih terbiasa dengan Merkurius, dan saya pikir "model minimal tabling" Merkurius adalah persis apa yang Anda butuhkan untuk kasus ini. Saya tidak pernah benar-benar menggunakannya, tetapi pemahaman saya lebih atau kurang memungkinkan istilah yang menyiratkan dirinya dianggap benar jika ada beberapa cara lain untuk membuktikannya, atau salah jika tidak, tanpa terjebak dalam loop yang tak terbatas. Lihat bagian yang relevan dari dokumen Merkurius, dan jika Anda tertarik makalah yang menjelaskan implementasinya.
Merkurius adalah bahasa pemrograman logis yang dipaksakan dengan kemurnian murni, dengan sintaksis yang mirip dengan Prolog tetapi tipe dan sistem mode yang kuat, dan dikompilasi daripada ditafsirkan.
Saya baru saja membaca ulang pengantar makalah (yang belum saya baca sebentar lagi), dan itu menyebutkan tabling telah diimplementasikan dalam beberapa versi Prolog, jadi mungkin Anda bisa melangkah lebih jauh dengan googling untuk tabling dalam Prolog.
sumber
Saya menemukan makalah berikut tentang pemecahan SAT menggunakan prolog:
Implementasi solver dapat ditemukan di sini .
Lihat jawaban stackoverflow ini untuk perincian tentang kode dan cara menggunakannya.
sumber
Mengesampingkan masalah huruf kecil / huruf besar, ada siklus dalam klausa:
Jadi, ketika Anda memanggil penerjemah top-down, itu akan berulang. Anda mungkin lebih beruntung dengan Answer Set Programming (ASP), yang berfungsi dari bawah ke atas. Berikut ini adalah pengkodean via perpustakaan ( minimal / asp ):
Ini adalah contoh run:
sumber