技術雜談:Faster Prolog in Perl with Yaswi

PUBLISHED ON SEP 2, 2014

    In my previous post, I introduced AI::Prolog, a Prolog engine written in Perl. AI::Prolog is easy to use; however, the speed may be not satisfying. Language::Prolog::Yaswi refers to Yet Another interface to SWI-Prolog; the performance of Language::Prolog::Yaswi is better than that of AI::Prolog.

    Before using Yaswi, You need a SWI-Prolog complier in your system. You can get it from SWI-Prolog website.

    First, you need to write a Prolog knowledge base. You may write it in the Perl script of in a seperated file. Say we have a knowledge base file train.pro.

    directTrain(saarbruecken,dudweiler).
    directTrain(forbach,saarbruecken).
    directTrain(freyming,forbach).
    directTrain(stAvold,freyming).
    directTrain(fahlquemont,stAvold).
    directTrain(metz,fahlquemont).
    directTrain(nancy,metz).
    
    travelFromTo(X,Y) :- directTrain(X,Y).
    travelFromTo(X,Z) :-
        directTrain(X,Y),
        travelFromTo(Y,Z).

    Second, you have to load the knowledge base. In this case, we also load :query for later use.

    use Language::Prolog::Yaswi qw(:load :query);
    
    swi_consult 'kb_train.pro';

    If you want to directly write your knowledge base into the Perl script, use swi_inline.

    use Language::Prolog::Yaswi qw(:load :query);
    
    swi_inline <<"END_OF_PROLOG";
    directTrain(saarbruecken,dudweiler).
    directTrain(forbach,saarbruecken).
    directTrain(freyming,forbach).
    directTrain(stAvold,freyming).
    directTrain(fahlquemont,stAvold).
    directTrain(metz,fahlquemont).
    directTrain(nancy,metz).
    
    travelFromTo(X,Y) :- directTrain(X,Y).
    travelFromTo(X,Z) :-
        directTrain(X,Y),
        travelFromTo(Y,Z).
    END_OF_PROLOG

    Then, you can query the knowledge base. The query are wrapped by Language::Prolog::Sugar. Therefore, you may follow the document there. Finally, print out the result.

    use Language::Prolog::Sugar
        vars => [qw(X Z)],
        functors => {travelFromTo => 'travelFromTo'};
    
    swi_set_query(travelFromTo('metz', Z));
    while (swi_next) {
        printf "From: metz, To: %s\n", swi_vars(Z);
    }

    For extra credit, I write a Perl script to compare the performance difference between Language::Prolog::Yaswi and AI::Prolog. Obviously, the former outperforms the latter much.

    Benchmark: timing 1000 iterations of by ai prolog, by yaswi...
    by ai prolog: 34 wallclock secs (33.48 usr +  0.07 sys = 33.55 CPU) @ 29.81/s (n=1000)
      by yaswi:  0 wallclock secs ( 0.41 usr +  0.01 sys =  0.42 CPU) @ 2380.95/s (n=1000)