Skip to content
Lyndon Henry edited this page Oct 30, 2019 · 1 revision

Why do we need C++ interface?

Applications may want to integrate Soufflé programs as a library rather than as a stand-alone tool. For this purpose, we have developed a C++ interface to call Soufflé programs.

With the option -g <name>.cpp a C++ class is generated for a Soufflé program that can be directly embedded in another C++ application. The generated class may have several instances. An instance provides interfaces to populate input relations, to run the program, and to retrieve data from the output relations. Note that the generated class is required to be compiled with the flag __EMBEDDED_SOUFFLE__ to disable the default main() function of a Soufflé program.

How to use C++ interface?

Step 1. Generate a C++ instance

After a Souffle program has been written and stored in a datalog file, a c++ file can be generated for this Souffle program with the option -g <name>.cpp in the command line. After this, an instance of the c++ class of this Soufflé program can be generated by executing the following code: #include "souffle/SouffleInterface.h"

if(souffle::SouffleProgram *prog=souffle::ProgramFactory::newInstance("<name>")) {
/* populate input relations */
/* run a program */
/* retrieve data from output relations */
/* other functionalities*/ delete prog;
} else {
std::cerr << "Failed to create instance for program <name>\n";
exit(1);
}
"" is the name of a Souffle programs. If an instance is created sucessfully, a pointer to the instance of the SouffleProgram class is returned and stored in the variable prog.

Step 2. Call functions provided in the interface by using this instance

The functions provided in the interface can be found in SouffleInterface.h file. In this file, there are four classes, tuple, relation, SouffleProgram, and ProgramFactory each with functions that can be called. As mentioned before, variable prog is a pointer to an instance of SouffleProgram. The functions prog can call are the public functions defined in the SouffleProgram class in SouffleInterface.h file. The functions are called by "prog->".

2.1. Populate Input Relations

There are two ways to populate input relations.

The first way is through loading data from CSV files and then inserting them to the relations by using loadAll() function. This functionality is executed by invoking the code

prog->loadAll("<dir>");

The directory <dir> represents the input directory where the input files of the relations are located.

The second way is through creating the tuples objects, adding data to them, and then using insert() function to insert the tuples objects into the relation.

if(souffle::Relation *rel = prog->getRelation("<rel-name>")) { : get relation reference
souffle::tuple newTuple(rel); : create tuple for the relation

Place integers/symbols into the relation using << operator. The arity and the data type of the variables have to follow the relation "my-rel" correspondingly.
newTuple << "TestData" << 10;

rel->insert(newTuple); : insert tuple into relation
}

2.2. Run the program

A Soufflé program is executed invoking the run() function, e.g..,

#include "souffle/SouffleInterface.h"

if(souffle::SouffleProgram *prog=souffle::ProgramFactory::newInstance("<name>")) {
prog->loadAll("."); : load from current directory
prog->run(); : run catalog program
/* retrieve data from output relations */
delete prog;
} else {
std::cerr << "Failed to create instance for program <name>\n";
exit(1);
}

2.3. Retrieve output relations

Output relations can be accessed via the container provided by the relation. The current tuple provides stream operators to write data into variables.

if(souffle::Relation *rel = prog->souffle::getRelation("<my-rel>")) {
for(auto &output : *rel ) {
output >> var1 >> var2;
}
}

Alternatively, the function prog->printAll() writes the contents of the output relations to their defined destinations.

2.4. Check the existence of tuples in relations

Check whether a tuple exists in relation by using the contains() function.

if(souffle::Relation *rel = prog->souffle::getRelation("<my-rel>")) {
tuple test(rel); : Create a tuple for further checking
test << "A" << 123;

if (rel->contains(test)) { : Check if "my-rel" contain a tuple {"A", 123}
...
}
}

Alternatively, the function size() indicates the number of tuples in a relation, the function getSignature() returns the attribute type of the relation.