Sicstus Prolog – Building a Windows Executable

Written by on August 19, 2018 in Natural Language Processing, Programming, Prolog with 0 Comments

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):

Creating WordNet Prolog Image

Creating WordNet Prolog Image

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 engine
if (SP_FAILURE == SP_initialize(0, NULL, NULL)) {
cout << “Init error\n”;
return -1;
}
// Load the saved WordNet program image
int 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” predicate
SP_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 alone
SP_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 predicate
SP_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 predicate
if (!(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 solutions
while (SP_next_solution(goal) == SP_SUCCESS) {
SP_integer sid;
// We are interested in synset ID
SP_get_integer(synset_id, &sid);
cout << “Solution found. ID is: ” << sid << endl;
// Nested query – let us find the gloss for matching IDs
if (!(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’ text
SP_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 query
SP_close_query(goal);
// Shut down the Prolog engine
SP_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.

Configuring VS2017

Configuring VS2017

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).

Running the Executable

Running the Executable

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!

Tags: ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published.

Top