In my previous post, I showed how to build a C-based Windows DLL to execute Prolog predicates in the Sicstus Prolog engine. Today, I want to show how to build an executable (on Windows) from a C/C++ program that uses Sicstus prolog engine.
The process is quite simple. In order to make things interesting, I am using a large-sized, real-world Prolog program to demonstrate this process. The example I will be using is the WordNet Prolog database (I downloaded the WNprolog-3.1.tar.gz file). The bundle contains documentation as well as Prolog files. There are 21 source files, out of which wn_s.pl and wn_sk.pl are the largest, with 207,202 predicates each.
First, I wrote a simple Prolog program to load all the WordNet Prolog files into Sicstus environment and save the final image as WordNet.sav file. That way, it is convenient and faster to eventually load the full WordNet database into Sicstus environment. Here is the program that does that (all referenced files are available here):
Here is the C++ program (in spirit it is just C) that loads the WordNet image into Sicstus Prolog engine, invokes two predicates in a nested fashion and prints the results.
// Rangarajan Krishnamoorthy, August 16, 2018.// Example to create an Executable to load and run WordNet Prolog// files in Sicstus Prolog.//#include <sicstus/sicstus.h>#include <iostream>using namespace std;int main(){// Initialize the Prolog engineif (SP_FAILURE == SP_initialize(0, NULL, NULL)) {cout << “Init error\n”;return -1;}// Load the saved WordNet program imageint res = SP_restore(“WordNet.sav”);if (res == SP_ERROR || res == SP_FAILURE) {cout << “Restore error\n”;return -2;}SP_qid goal, goal2;SP_term_ref synset_id, wnum, ss_type, sense_num, tag_count, word;// Create the “s” predicateSP_pred_ref s_pred = SP_predicate(“s”, 6, NULL);// Let us lookup the synset IDs for the word “lion”SP_put_string(word = SP_new_term_ref(), “lion”);// To keep things simple, let us restrict to “noun” form aloneSP_atom pos = SP_atom_from_string(“n”);SP_put_atom(ss_type = SP_new_term_ref(), pos);// Assign suitable variables to other arguments of the predicateSP_put_variable(synset_id = SP_new_term_ref());SP_put_variable(wnum = SP_new_term_ref());SP_put_variable(sense_num = SP_new_term_ref());SP_put_variable(tag_count = SP_new_term_ref());// Let us create another predicate for getting the “gloss”SP_pred_ref g_pred = SP_predicate(“g”, 2, NULL);SP_term_ref gloss;SP_put_variable(gloss = SP_new_term_ref());// Prepare to execute the predicateif (!(goal = SP_open_query(s_pred, synset_id, wnum, word, ss_type, sense_num, tag_count))) {cout << “Open ‘s’ query error\n”;return -3;}// Keep trying for solutionswhile (SP_next_solution(goal) == SP_SUCCESS) {SP_integer sid;// We are interested in synset IDSP_get_integer(synset_id, &sid);cout << “Solution found. ID is: ” << sid << endl;// Nested query – let us find the gloss for matching IDsif (!(goal2 = SP_open_query(g_pred, synset_id, gloss))) {cout << “Open ‘g’ query error\n”;continue;}while (SP_next_solution(goal2) == SP_SUCCESS) {const char *gloss_str = NULL;// We are interested in the ‘gloss’ textSP_get_string(gloss, &gloss_str);cout << “Gloss = ” << gloss_str << endl;}// Nested query must be closed before continuing with the higher level query.SP_close_query(goal2);}// Close the querySP_close_query(goal);// Shut down the Prolog engineSP_deinitialize();return 0;}
The above program (WordNetExample.cpp) prints the Synset ID and its corresponding gloss for the word lion, for Noun part of speech. The logic is fairly straightforward and I hope the comments make the program easier to understand. Detailed information about the various runtime functions is available in the official Sicstus documentation (in my installation, it is sicstus.pdf).
The next step is to launch the command prompt and configure the Visual Studio 2017 64 bit environment. We did this as part of building the DLL in the previous post, but here it is again.
Sicstus Prolog BIN directory is assumed to be in the PATH. Next, CD to the directory where the our C++ file is located. Execute the following command:
> spld –main=none WordNetExample.cpp -o WordNetExample.exe
It is important to set the main option to none. This causes our main to be executed.
It takes just a few seconds to create the output file.
Before running the program, we have to make sure that the file WordNet.sav is in the same directory as the executable (remember we have not hardcoded any other path).
As expected, the program prints the Synset ID and gloss for the two (Noun) senses of the word lion.
Once thing I really like about Sicstus Prolog is its performance. It took a mere 1.22 seconds to load the saved image (containing 21 Prolog files in compiled format) in its IDE. As a commercial product, it is widely respected for its speed. As part of my iLexicon project, I have several Prolog files containing descriptions of a large number (around 300 thousand) of English words, and Sicstus Prolog loads all of them effortlessly. Sicstus’ official benchmarks may be found here.
Files referenced in today’s post (other than WordNet files) maybe downloaded from here. WordNet Prolog files can be downloaded from here.
Have a nice weekend!
Recent Comments