Kết nối SWI-Prolog với Java/C#


[Updated2-Jan,03,2017] Sau loạt 4 bài Nhập môn XLNNTN, bạn hãy tự kiểm tra kiến thức của bản thân qua đề bài như sau: (Đề đồ án cuối kỳ môn XLNNTN)

Cho các câu huấn luyện:
– Năm học đại học ở thành phố.
– Nam học ngành CNTT.
– Nó sắp thi học kỳ.
– Nó đang học bài.
– Lan học với Nam.
– Họ đang học ở trường.
– Lan đã về nhà.
– Lan và Nam đã học bài.
– Nam về nhà và đọc sách.
– Nam thường nói chuyện với Lan.
Yêu cầu: Xây dựng một mini parser bằng cách định nghĩa một văn phạm DCG thực thi trên Prolog. Testing: tất cả các câu mở rộng (mới) của 10 câu huấn luyện đã cho.

Nếu bạn đã theo dõi bài blog về XLNNTN của mình thì giải quyết được đề này gồm các bước : Xây dựng cây cú pháp, Chuyển sang văn phạm DCG, Gộp văn phạm DCG. Nhưng để đạt điểm tốt và hứng thú hơn ta sẽ phải xây dựng giao diện, tức là không truy vấn và thao tác trên Swipl Prolog nữa, thay vào đó bạn sẽ sử dụng ngôn ngữ Java C# hay Python để xây dựng một chương trình có giao diện trực quan, sinh động,… Vậy là mình phải google, bing để tìm hiểu. Ở chủ đề này, mình sẽ hướng dẫn các bạn kết nối swipl với C# và Java. Nào thực hiện thôi 😛

Cài đặt SWI- Prolog tại địa chỉ: http://www.swi-prolog.org/Download.html chọn phiên bản phù hợp. Mình đang sử dụng bản Development release (version 7.3.x), máy mình sử dụng Windows 64bit nên sau khi cài đặt, Swipl sẽ nằm trong đường dẫn C:\Program Files (x86)\swipl (lưu ý đường dẫn này nhé, sẽ dùng sau).
Với đề bài trên, sau khi Gộp văn phạm DCG ta sẽ gõ vào Swipl Prolog, bạn lưu ý trong blog này sẽ chuẩn bị 2 file .pl với yêu cầu: (cách thực hiện xem tại đây)
+ XLNNTN1.pl: truy vấn kết quả ra true false, văn phạm DCG thông thường

s-->np,vp.
np-->nnp.
np-->nn.
np-->nn,nn.
np-->ppr.
np-->nnp,c,nnp.

vp-->vb,vp.
vp-->np,pp.
vp-->vb,np.
vp-->rb,vp.
vp-->vb,pp.
vp-->rb,vb,np.
vp-->np,vp.
vp-->c,vp.
pp-->in,np.

ppr-->[no].
ppr-->[ho].
nnp-->[nam].
nnp-->[lan].

nn-->[nganh].
nn-->[cntt].
nn-->[dai,hoc].
nn-->[thanh,pho].
nn-->[hoc,ky].
nn-->[bai].
nn-->[truong].
nn-->[nha].
nn-->[sach].

vb-->[hoc].
vb-->[thi].
vb-->[hoc].
vb-->[ve].
vb-->[noi,chuyen].
vb-->[doc].

in-->[o].
in-->[voi].
rb-->[sap].
rb-->[dang].
rb-->[da].
rb-->[thuong].
c-->[va].
 

+ XLNNTN2.pl: truy vấn kết quả ra dạng List, văn phạm DCG list

s(s(NP,VP))-->np(NP),vp(VP).
np(np(NNP))-->nnp(NNP).
np(np(NN))-->nn(NN).
np(np(NN1,NN2))-->nn(NN1),nn(NN2).
np(np(PPR))-->ppr(PPR).
np(np(NNP1,C,NNP2))-->nnp(NNP1),c(C),nnp(NNP2).

vp(vp(VB,VP))-->vb(VB),vp(VP).
vp(vp(NP,PP))-->np(NP),pp(PP).
vp(vp(VB,NP))-->vb(VB),np(NP).
vp(vp(RB,VP))-->rb(RB),vp(VP).
vp(vp(VB,PP))-->vb(VB),pp(PP).
vp(vp(RB,VB,NP))-->rb(RB),vb(VB),np(NP).
vp(vp(NP,VP))-->np(NP),vp(VP).
vp(vp(C,VP))-->c(C),vp(VP).
pp(pp(IN,NP))-->in(IN),np(NP).

ppr(ppr(no))-->[no].
ppr(ppr(ho))-->[ho].
nnp(nnp('Nam'))-->[nam].
nnp(nnp('Lan'))-->[lan].

nn(nn(nganh))-->[nganh].
nn(nn('CNTT'))-->[cntt].
nn(nn('dai hoc'))-->[dai,hoc].
nn(nn('thanh pho'))-->[thanh,pho].
nn(nn('hoc ky'))-->[hoc,ky].
nn(nn(bai))-->[bai].
nn(nn(truong))-->[truong].
nn(nn(nha))-->[nha].
nn(nn(sach))-->[sach].

vb(vb(hoc))-->[hoc].
vb(vb(thi))-->[thi].
vb(vb(hoc))-->[hoc].
vb(vb(ve))-->[ve].
vb(vb('noi chuyen'))-->[noi,chuyen].
vb(vb(doc))-->[doc].

in(in(o))-->[o].
in(in(voi))-->[voi].
rb(rb(sap))-->[sap].
rb(rb(dang))-->[dang].
rb(rb(da))-->[da].
rb(rb(thuong))-->[thuong].
c(c(va))-->[va].
 

*Note:

Cuối bài viết có tip ngắn: “Hướng dẫn cho các bạn dùng hệ điều hành dựa trên Ubuntu (Linux mint/Kali…) kết nối Java với Swi-Prolog” đóng góp hữu ích từ bạn Lê Lâm.


C#

* Chuẩn bị:
– Truy cập http://www.swi-prolog.org/contrib/CSharp.html tải file “SwiPlCs 1.1.60301.0.zip” (truy cập lần cuối May 13, 2016 @ 21:54:00) và giải nén.
– Truy cập http://nunit.org/index.php?p=download tại  Current Release, ở dòng bin bấm tải “NUnit-3.2.1.zip” (truy cập lần cuối May 14, 2016 @ 17:15:00) và giải nén.
– Công cụ không thể thiếu cuối cùng là Visual Studio
* Thực hành:
– Chúng ta sẽ tạo ra một chương trình với 2 chế độ truy vấn: Kết quả ra True/False; kết quả trả về dạng list. Nhưng ở phần này, chỉ demo chương trình với chế độ trả về kết quả True/False.
– Mở Visual Studio: Chọn FILE -> New -> Project… ->Trong Visual C#, chọn Windows -> Windows Forms Application. Đặt tên project, chọn đường dẫn để lưu, đặt tên Solution name -> Nhấn OK để tạo Project

  • Ở thư mục “SwiPlCs 1.1.60301.0.zip” đã giải nén, copy file “SwiPlCs64.dll” nếu là Windows 64bit/ “SwiPlCs.dll” nếu Windows 32bit và paste vào Thư mục chứa Project (ví dụ: E:\WindowsFormsApplication1).
  • Trong thư mục “NUnit-3.2.1” đã giải nén, chọn bin, copy file “nunit.framework.dll” (…Downloads\NUnit-3.2.1\bin) và paste vào Thư mục chứa Project (ví dụ: E:\WindowsFormsApplication1 ).
  • Trong Solution Explorer tab: Chọn Project đã tạo, Click chuột phải vào References -> Add References… -> Chọn nút Browse… và đi tới, chọn 2 file.dll đã paste trước đó ->OK.
  • Chuột phải vào project -> Add -> New Item… -> Installed -> Visual C# Items -> chọn Class và đặt tên file “Load_Result.cs” -> bấm nút Add.
  • Trong Class vừa tạo ta thực hiện tổ chức code như sau:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SbsSW.SwiPlCs; //thu vien ket noi Prolog voi C#
using NUnit.Framework; //thu vien ho tro
using System.Text.RegularExpressions; //thu vien ho tro

namespace Load_Result
{
 class LoadResult
 {
 public void LoadFile(string s)
 {
 s = "consult('" + s + "')";
 string query = s.Replace("\\", "//"); //Xu ly duong dan
 string[] p = { "-q", "-f", query };
 PlEngine.Initialize(p);
 try
 {
 PlQuery q = new PlQuery(query);
 Assert.IsTrue(q.NextSolution());
 }
 catch (SbsSW.SwiPlCs.Exceptions.PlException e)
 {
 System.Windows.Forms.MessageBox.Show(e.ToString(), "Lỗi");
 }
 }

 public string Result(string s)
 {
 s.Trim();
 Regex r = new Regex(@"[A-Z_][a-zA-Z_]*");
 MatchCollection matches = r.Matches(s);
 string result = "";
 try
 {
 PlQuery q = new PlQuery(s);
 bool HasSolution = false;
 foreach (PlQueryVariables v in q.SolutionVariables)
 {
 HasSolution = true;
 foreach (Match match in matches)
 {
 result += match.ToString() + " = " + v[match.ToString()].ToString() + ";";
 }
 }
 if (matches.Count == 0)
 return HasSolution ? "true" : "false";
 return result;
 }
 catch (SbsSW.SwiPlCs.Exceptions.PlException ex)
 {
 return "Error query: " + ex.Message;
 }
 }

 }
}
  • Tạo giao diện như sau
    prologc#_
  • Nhấp đúp 2 lần vào button “Nạp File” và “Truy vấn” (Chú ý sửa lại thuộc tính (Name) trong khu vực Properties của các button – bt_load & bt_query và textbox Truy vấn: txtb_tv, Kết quả: txtb_kq). Trong file Form1.cs tổ chức code như sau:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SbsSW.SwiPlCs;
using NUnit.Framework;
using Load_Result;

namespace WindowsFormsApplication1
{
 public partial class Form1 : Form
 {
 Load_Result.LoadResult ketnoi;
 public Form1()
 {
 ketnoi= new LoadResult();
 InitializeComponent();
 }

 private void bt_load_Click(object sender, EventArgs e)
 {
 OpenFileDialog op = new OpenFileDialog();
 op.Filter = "Prolog file|*.pl";
 op.ShowDialog();
 String FilePath = op.FileName;
 ketnoi.Loadfile(FilePath);
 MessageBox.Show("Nạp file thành công !");
 this.bt_query.Enabled = true;

 }

 private void bt_query_Click(object sender, EventArgs e)
 {
 if (this.txtb_tv.Text != null)
 {
 String s = ketnoi.Result(this.txtb_tv.Text);
 this.txtb_kq.Text = s;
 }
 else
 {
 MessageBox.Show("Xin nhập truy vấn!");
 }
 }
 }
}
  • Trong file “Form1.cs” thêm đoạn code sau vào hàm “Form1_Load” như sau:
 //Environment.SetEnvironmentVariable("SWI_HOME_DIR", @"the_PATH_to_boot64.prc");
 // C:\\Program Files (x86)\\swipl la duong dan toi boot32.prc
 // Neu ban dang su dung W32bit duong dan se la C:\\Program Files\\swipl
 Environment.SetEnvironmentVariable("SWI_HOME_DIR", @"C:\\Program Files (x86)\\swipl");
 Environment.SetEnvironmentVariable("Path", @"C:\\Program Files (x86)\\swipl");
 Environment.SetEnvironmentVariable("Path", @"C:\\Program Files (x86)\\swipl\\bin");
  • Bước cuối cùng, bạn copy file “XLNNTN1.pl” đã chuẩn bị vào đường dẫn file project E:\WindowsFormsApplication1\ (không làm bước này cũng được vì ta sẽ chọn file.pl sau khi khởi động chương trình).
  • Bạn hãy chạy thử và xem kết quả: Đầu tiên nhấp “Nạp file” chọn file “XLNNTN1.pl” =>nhập cấu trúc truy vấn (vd: s([no,hoc,nganh,cntt],[]).  )   => nhấp “Truy vấn” => Kết quả 😛

Lưu ý: Với một số bài hướng dẫn khác, các file “XLNNTN1.pl“, “SwiPlCs64.dll“, “nunit.framework.dll” được copy vào thư mục Debug theo đường dẫn
E:\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug
 .

Chúng ta đã hoàn thành một chương trình bằng C# kết nối Prolog, trả về kết quả True/False. Nếu đang bắt đầu chạm vào kiến thức của Xử lý ngôn ngữ tự nhiên thì chương trình này rất có lợi khi bạn muốn kiểm tra các cú pháp của mình có đúng hay không mà không cần mở Command Line của SWI-Prolog 🙂


JAVA

* Chuẩn bị:
– Kiểm tra trong thư mục lib ở đường dẫn C:\Program Files (x86)\swipl\lib (Win32: C:\Program Files \swipl\lib) có file jpl.jar hay không (file này có sẵn khi cài đặt SWI-Prolog). Nếu không có, à mà chắc chắn sẽ có hihi.
– Thiết lập biến môi trường:  Chuột phải vào “My computer – hoặc This PC/Computer” -> properties -> “Advanced system settings” -> Chọn Tab “Advanced” -> “Environment Variables…” -> Trong mục “User variables for Phams” bạn kiểm tra xem đã có Variable là “PATH” hay chưa, nếu chưa có thì chọn “New…” -> Xuất hiện cửa sổ “New User Variable” và điền như sau:

+ Variable name: PATH
+ Variable value:
C:\Program Files (x86)\swipl\bin;%SWI_HOME_DIR%\bin;%SWI_HOME_DIR%\lib\jpl.jar
Nếu đã có biến “PATH” rồi, bạn click chọn dòng “PATH” đó -> Edit… -> Chọn New -> và điền đường dẫn
C:\Program Files (x86)\swipl\bin;%SWI_HOME_DIR%\bin;%SWI_HOME_DIR%\lib\jpl.jar” ->OK.  Cũng tại “Environment Variables…” ->”New…

+ Variable name: SWI_HOME_DIR
+ Variable value: C:\Program Files (x86)\swipl

Nhấp OK -> OK, đóng các cửa sổ thiết lập lại. Nên khởi động lại máy ^^

* Thực hành:
NetBeans IDE: (Eclipse below)

– Khởi chạy NetBean, trên thanh công cụ chọn Tools -> Libraries -> New Library… -> Đặt tên Library name: JPL ->OK . Nhìn bên phải cửa sổ: Ant Library Manager, bấm chọn Add JAR /Folder… ,tìm đến file “jpl.jar” trong thư mục “lib” ở đường dẫn “C:\Program Files (x86)\swipl\lib ” và chọn Add JAR/Folder -> OK.
prologjavalib
– Tạo mới 1 dự án java: File -> New Project… -> chọn Java -> Java Application -> Next> -> Nhập tên dự án, và thông tin tuỳ chỉnh -> Finish. Tại tab Project, chuột phải vào Libraries -> Add JAR/Folder… ->chọn file jpl.jar ở thư mục lib  -> Open .. và ta thấy jpl.jar đã xuất hiện trong folder Libraries.

Tạo class và tổ chức code như sau:

.... updating
...

Eclipse IDE:

– Khởi động Eclipse, Chọn Help -> Install New Sofware… -> Add. Tại trường name nhập tên “Prolog“, Location: nhập đường dẫn “http://sewiki.iai.uni-bonn.de/public-downloads/update-site” ->OK.

– Mở danh sách “Program Analysis and Transformation” vi “Prolog Development Tool (PDT)”. Chn 2 mc “JTransformer” và “Prolog Development Tools“. Nhấn Next và cài đặt.

– Tạo mới project….
– Sau khi đã tạo 1 empty project, nhấp chuột phải vào project, chọn New->File-> đặt tên file.pl (vd: swiljava.pl). Viết code trong file pl vừa tạo và save lại.
– Từ menu Prolog, chọn Prolog Console
– Chọn “Prolog” -> (re)consult-> xuất hiện predicate trong cửa sổ outline.
– Tại Project Console, viết vài câu truy vấn
– Để debug gõ noguitracer. sau đó gõ trace,p(X,Y,Z).
Link hướng dẫn http://sewiki.iai.uni-bonn.de/research/pdt/connector/start
http://www.swi-prolog.org/packages/jpl/java_api/javadoc/jpl/Query.html
http://www.swi-prolog.org/packages/jpl/java_api/getting_started.html
http://www.swi-prolog.org/packages/jpl/

https://www.youtube.com/watch?v=MP9weU4NBYE
https://www.youtube.com/watch?v=oN0rz37vrlg


Bài viết đóng góp từ bạn Lâm

– Bạn cài swi-prolog-java trong kho phần mềm.
– Thêm vào .bashrc 2 dòng sau (nhớ đăng xuất rồi vào lại để nạp lại các biến môi trường)

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/swi-prolog/lib/amd64"
export CLASS_PATH="$CLASS_PATH:/usr/lib/swi-prolog/jpl.jar"

Để chắc ăn có thể cho jpl trong /usr/lib/swi-prolog vào trong thư mục project cũng được.
Trong project:

// Dòng này dùng để mở liên kết tới file pl
Query q1 = new Query(“consult(' " + duong_dan_den_file_pl +" ')”);

// Dòng này để kiểm xem bạn đã liên kết được với file pl hay chưa
System.out.print("Open?" + q1.hasSolution()? "Yes":"No");

Để truy vấn cú pháp DCG ta làm như sau:
Query q2 = new Query(cau_truy_van);

// Tạo mảng map lưu kết quả truy vấn
Map[] solutions = q2.allSolutions();

// In ra toàn bộ các cú pháp DCG của câu truy vấn
for (int i = 0 ; i < solutions.length; ++i) {
System.out.println(“X = ” + solutions[i].get(“X”) + “\n”);
}

 

 

Chúng ta đã thực hiện xong bài hướng dẫn Kết nối Prolog với 2 ngôn ngữ Java và Csharp, hy vọng nó là tiền đề để bạn có thể nghiên cứu sâu hơn. Bất cứ thắc mắc hay ý kiến bạn comment dưới bài viết nhé. OK, hẹn gặp lại


Cảm ơn bạn đã theo dõi blog.
Nhiều ngày tốt lành!

9 thoughts on “Kết nối SWI-Prolog với Java/C#

  1. Hướng dẫn cho các bạn dùng hệ điều hành dựa trên Ubuntu (Linux mint/Kali…) kết nối Java với Swi-Prolog:
    – Bạn cài swi-prolog-java trong kho phần mềm.
    – Thêm vào .bashrc 2 dòng sau (nhớ đăng xuất rồi vào lại để nạp lại các biến môi trường)

    export LD_LIBRARY_PATH=”$LD_LIBRARY_PATH:/usr/lib/swi-prolog/lib/amd64″
    export CLASS_PATH=”$CLASS_PATH:/usr/lib/swi-prolog/jpl.jar”

    Để chắc ăn có thể cho jpl trong /usr/lib/swi-prolog vào trong thư mục project cũng được.
    Trong project:

    // Dòng này dùng để mở liên kết tới file pl
    Query q1 = new Query(“consult(‘” + duong_dan_den_file_pl +”‘)”);

    // Dòng này để kiểm xem bạn đã liên kết được với file pl hay chưa
    System.out.print(“Open?” + q1.hasSolution()? “Yes”:”No”);

    Để truy vấn cú pháp DCG ta làm như sau:
    Query q2 = new Query(cau_truy_van);

    // Tạo mảng map lưu kết quả truy vấn
    Map[] solutions = q2.allSolutions();

    // In ra toàn bộ các cú pháp DCG của câu truy vấn
    for (int i = 0 ; i < solutions.length; ++i) {
    System.out.println(“X = ” + solutions[i].get(“X”) + “\n”);
    }

    Like

  2. Bạn cho mình tham khảo phần truy vấn kết quả ra dạng List, văn phạm DCG list không? Mình cần xuất câu trả lời thay vì trả kết quả True/False

    Like

  3. Exception in thread “main” java.lang.UnsatisfiedLinkError: jpl.fli.Prolog.thread_self()I
    at jpl.fli.Prolog.thread_self(Native Method)
    at jpl.Query.open(Query.java:286)
    at jpl.Util.textToTerm(Util.java:162)
    at jpl.Query.(Query.java:198)
    at connectprolog.Connect.connectProlog(Connect.java:22)
    at connectprolog.ConnectProlog.main(ConnectProlog.java:24)
    C:\Users\kioch\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1

    tui chạy netbean 8.2 file kết nói giữa swi prolog với java nó lỗi z có ai pit sữa sao chỉ mình với

    Like

Cho mình biết cảm nhận của bạn nhé