Conga
Home
Contact
Teaching
Publications
Conga
Source Control
TeAL/ChoiceNet
Conga — a portmanteu of "convergent grounder" — is a new answer set programming language and grounder. The language itself — heavily influenced by KU Leuven's
IDP2 exposes answer set programming via first order logic semantics (with extensions to make the actual programming a bit more pleasant, such as a full suite of arithmetic operations, aggregation of atoms, and an extended existential quantifier).
I began working on conga in 2012 under the direction of
Mirek Truszczyński, designing and implementing a grounder for the
IDP2 answer set programming language. In 2013 (inspired by a conversation with
Marc Denecker), the project expanded to its current focus — the conga answer set programming language and the conga C++ class library, both designed and implemented by me.
In addition to the logical connectives shown to the right, conga follows C-style arithmetic operators (and thus == for comparison) and follows C's rules for operator precedence.
Thus far, the conga command line tool implements the conga language, as well as IDP2 at near 100% functionality. Work is ongoing in implementing the
ASP-Core-2 standard.
Conga can be a bit more verbose than other answer set programming grounders, as it requires explicit declaration of variables, but otherwise conga programs tend to be of similar size of programs in other answer set programming languages.
So, without further ado, here's an example conga program which solves a sudoku board:
type Tile(1, 9);
type Index(0, 8);
type Space(0, 80);
predicate Location(Space, Tile);
predicate Row(Space, Index);
predicate Column(Space, Index);
predicate Square(Space, Index);
var t(Tile), s(Space), i(Index);
forall(s), exists(t).exactly(1), Location(s, t);
forall(s), forall(i), Row(s, i) = ((s / 9) == i);
forall(s), forall(i), Column(s, i) = ((s % 9) == i);
forall(s), forall(i), Square(s, i) = ((((s / 9) / 3) * 3) + ((s % 9) / 3) == i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Column(s, i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Row(s, i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Square(s, i);
conga::hideall();
conga::show(Location);
However, in the grand scheme of things,
this isn't all that exciting; I'll be the first to admit that the syntax of
IDP3 is more elegant, and the field as a whole appears to be moving away from the concept of new languages (or, at least, new
divergent languages) inasmuch as the acceptance of the
ASP-Core-2 project is receiving support.
But! This isn't the interesting part of conga. In fact, the inelegance of the syntax of the stand-alone language is a result of the language's main design goal: In addition to existing as a standalone grounder, it also exists as a C++ class library which uses the
exact syntax in C++. So, with the proper headers included and libraries linked, we can convert the above logic program into the following C++ function:
bool solvePuzzle(vector & vPuzzle, bool & bMore)
{
// Logic program starts here
conga::beginTheory();
type Tile(1, 9);
type Index(0, 8);
type Space(0, 80);
predicate Location(Space, Tile);
predicate Row(Space, Index);
predicate Column(Space, Index);
predicate Square(Space, Index);
var t(Tile), s(Space), i(Index);
forall(s), exists(t).exactly(1), Location(s, t);
forall(s), forall(i), Row(s, i) = ((s / 9) == i);
forall(s), forall(i), Column(s, i) = ((s % 9) == i);
forall(s), forall(i), Square(s, i) = ((((s / 9) / 3) * 3) + ((s % 9) / 3) == i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Column(s, i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Row(s, i);
forall(i), forall(t), exists(s).exactly(1), Location(s, t) && Square(s, i);
forall(s), forall(t), func(function([&]() {return vPuzzle[s()] == t(); })) >> Location(s, t);
conga::hideall();
conga::show(Location);
// Logic program done, back to procedural code
if (!conga::solve())
{
return false;
}
for (auto it : Location)
{
vPuzzle[it[0]] = it[1];
}
// Test if the solver found multiple solutions
bMore = conga::more();
return true;
}
Which gives us a perfectly normal C++ function which takes a vector of ints (representing a sudoku board), builds a theory, grounds it, solves it, and returns the results in a standard C++ collection class.
Of particular interest in the above code is the line:
forall(s), forall(t), func(function([&]() {return vPuzzle[s()] == t(); })) >> Location(s, t);
Sudoku puzzle of the day - February 15th
3
9
6
4
1
8
2
7
5
8
7
4
5
2
6
3
9
1
5
1
2
7
3
9
8
4
6
1
2
7
3
6
5
9
8
4
6
3
8
1
9
4
7
5
2
4
5
9
2
8
7
6
1
3
2
4
1
9
7
3
5
6
8
9
6
5
8
4
2
1
3
7
7
8
3
6
5
1
4
2
9
9
5
8
7
6
1
7
3
9
2
9
8
9
4
5
7
3
4
8
1
3
7
3
5
Which demonstrates what is likely the most powerful feature of the conga class library: the ability to embed "live" C++ code into a logic programming rule, and have that code executed during the grounding step. In this example the code performs a lookup in the vector passed to the solvePuzzle function, which then, during grounding, gets executed to evaluate the semantic value of the element.
An end result is the daily puzzle to the right — generated daily by the example source code
here.
A simpler example — solving a single puzzle given by the user as opposed to generating a whole puzzle — can be found
here.
Conga has been tested with and is fully functional compiled with GCC 4.7 or greater and Visual Studio 2012 (with the November 2012 Compiler CTP) or Visual Studio 2013. Other C++ compilers with robust C++11 support should work as well.
A public release is expected in the first quarter of 2014.