The clingo Input Language
Introduction
This section provides an overview of the input language of clingo, illustrating its constructs with concise examples.
|
Terms
Every logic program includes terms, which are mainly used to specify the arguments of atoms.
|
Basic Building Blocks
Basic terms are the fundamental elements used to construct expressions in clingo. They include integers, constants, strings, variables, and special tokens. Understanding these building blocks is essential for defining terms and expressing relationships within programs.
| Type | Description |
|---|---|
Integers |
Whole numbers, can be written in decimal, binary, octal, or hexadecimal. |
Constants |
Identifiers starting with a lowercase letter, may have underscores/ticks. |
Strings |
Text enclosed in double quotes, supports escape sequences. |
Variables |
Identifiers starting with uppercase letter, represent placeholders. |
Special tokens |
|
Integers
Integers can be written in various formats:
-
Optional minus sign followed by digits and optional thousands separators (apostrophes)
-
Binary (
0b), octal (0o), and hexadecimal (0x) notations -
Arbitrary length
p(42). % the integer 42
p(-42). % the integer -42
p(0b101011). % the integer 43
p(0o54). % the integer 44
% the integer 424242424242424242424242424242
p(0x55acd1bbd3529d94c1b26c9b2).
p(1'234'567). % the integer 1234567
Constants
Constants follow these rules:
-
Arbitrary prefix of underscores and ticks
-
Start with a lowercase letter
-
Arbitrary suffix of letters, digits, underscores, and ticks
p(a). % the constant a
p(_foo). % the constant _foo
p('_bar_Baz123'). % the constant '_bar_Baz123'
Strings
Strings are sequences of characters enclosed in double quotes. Escape sequences are supported:
-
\\for backslash -
\nfor newline -
\"for double quote
p("hello, world!").
p("line1\nline2").
p("She said: \"Hello!\"").
Variables
Variables are similar to constants but start with an uppercase letter after the
prefix. The special variable _ is anonymous; each occurrence is treated as a
different variable. Variables must receive a value in a rule.
p(X) :- X=1. % assigns 1 to variable X
p(_Foo) :- _Foo=2. % assigns 2 to variable _Foo
p('_Bar_Baz123') :- '_Bar_Baz123'=3. % assigns 3 to variable '_Bar_Baz123'
Infimum and Supremum
The tokens #sup and #inf (and their aliases #infimum and #supremum)
represent special values:
-
#inf: Smaller than any other term -
#sup: Larger than any other term
p(#inf).
p(#sup).
|
Compound Terms
Compound terms allow us to build more complex terms in clingo by combining basic terms using functions, tuples, format strings, and arithmetic expressions. These constructs enable richer modeling capabilities and facilitate the representation of structured information within logic programs.
Functions
A function term consists of:
-
A function symbol (like a constant)
-
Followed by a pool of arguments in parentheses
-
Pools are sequences of argument lists separated by semicolons
-
Argument lists are comma-separated sequences of terms
-
Empty argument lists are allowed, but pools must not be empty
A function symbol with an empty argument list is equivalent to a constant (parentheses are usually omitted).
p(f()). % the constant f (empty argument lists)
p(g(a,b)). % the function term g with argument list (a,b)
p(h(;1;2,3)). % the set of terms {h, h(1), h(2,3)} (pool notation)
Tuples
Tuples are similar to functions but without a function symbol.
-
Argument lists with one element are interpreted as terms in parentheses.
-
To indicate a one-element tuple, suffix with a comma.
p(()). % the empty tuple
p((1)). % the term 1
p((2,)). % the one-element tuple containing term 2
p((3,4)). % the two-element tuple containing terms 3 and 4
p((5;6,;7,8)). % the set of terms {5, (6,), (7,8)} (pool notation)
Format Strings
Format strings in clingo allow embedding expressions inside string literals,
enabling dynamic string construction. Expressions are enclosed in curly braces
{} and can include formatting options similar to Python’s
f-strings.
-
Basic usage:
f"string: {expr}"evaluatesexprand inserts its value. -
Conversion flags: Use
!rfor the representation (includes quotes) and!sfor the string conversion (removes quotes). -
Numeric formatting: Format numbers with type specifiers such as
d(decimal),b(binary),o(octal),x/X(hexadecimal), and#x(hexadecimal with prefix). -
Padding, alignment, and sign: Specify width, padding, align, sign, and separators, e.g.,
{12345:0=+8,}pads with zeros, sets numeric alignment, shows sign, sets width to 8, and uses comma as a thousands separator. -
Alignment: Use
<,>, or^for left, right, or center alignment, and specify a fill character. -
Attribute and item access: Expressions can access attributes of symbols.
-
Nesting: Format strings can be nested.
p(f"strings: {"foo"!r} - {"bar"!s}").
p(f"number: {42:d} - {42:b} - {42:o} - {42:x} - {42:X} - {42:#x}").
p(f"padding: {12345:0=+8,} {-12345:0=+8_}").
p(f"align: {abc:.^7} - {abc:.<7} - {abc:.>7}").
p(f"accessor: {f(g(h(1)))[0][0].name}").
p(f"nested: >{f"{7:0=3}"}<").
Arithmetic Terms
Arithmetic terms allow us to perform mathematical operations within clingo
programs. By combining basic terms with arithmetic operators, we can express
calculations that involve numeric values. They are formed using the following
connectives: +, -, , /, \, *,
~, ?, ^, &.
-
All connectives except exponentiation (
**) are left-associative. -
Precedence (from highest to lowest):
-
Unary
-,~(negation, bitwise negation) -
*,/,\(multiplication, integer division, modulo) -
+,-(addition, subtraction) -
?,^,&(bitwise or, xor, and) -
**(exponentiation)
-
-
Negated functions and constants evaluate to their corresponding negated symbol.
-
Invalid arithmetic terms evaluate to empty sets of terms.
p(1-2+3). % the term (1-2)+3=2
p(2**3**4). % the term 2**(3**4)=2417851639229258349412352
p(-1+2*3). % the term (-1)+(2*3)=5
p(-f). % the term -f
p(0-f). % the empty set of terms (invalid arithmetic term)
Absolute Terms
Absolute terms are non-empty sequences of terms separated by ; and
enclosed in | symbols.
-
An absolute term with more than one term represents the set of absolute values formed by evaluating the terms in the sequence.
-
Terms that do not evaluate to valid absolute values are ignored.
p(|-1|). % the term 1
p(|-2;3;-4|). % the set of terms {2, 3, 4}
p(|a|). % the empty set of terms (invalid term)
Interval Terms
Interval terms provide a concise way to specify ranges of integers.
-
An interval is written as
a..b, whereaandbare terms. -
The interval represents all integers from
atob, inclusive. -
If
aevaluates to a smaller integer thanbor one of the terms does not evaluate to an integer, the interval evaluates to the empty set. -
Intervals are left-associative and have the lowest precedence among term operators.
p(1..3). % the set of terms {1, 2, 3}
p(4..4). % the term 4
p(5..4). % the empty set of terms
Nested Pools
Pools can be nested, allowing surrounding terms to be constructed from all possible combinations of their elements.
% the set of terms {f(1), f(2), f(a)}
p(f(1..2;a)).
% the set of terms {1+3, 2+3, 1+6, 2+6} = {4, 5, 7, 8}
p((1..2)+(3;6)).
% the empty set {1,2} + {}
p((9..10)+(1+a)).
|
Basic Atoms and Literals
Having introduced the basic building blocks for constructing expressions, we now turn to atoms—the entities that form the core statements in logic programs.
Basic atoms or just atoms are the fundamental building blocks of logic programs. There are three main kinds of atoms:
-
Symbolic atoms, such as
p(1), which may also be classically negated as-p(3). -
Boolean atoms, which directly represent truth values:
#trueand#false. -
Comparison atoms, which compare terms using relations like
=,!=,<,<=,>, and>=.
A basic literal or just literal is any atom or its default-negated form.
Default negation is written as not atom and expresses the absence of evidence
for the atom. Double default negation, not not atom, is also allowed.
Default negation can be applied to:
-
symbolic atoms (including classically negated ones), e.g.,
not p(1),not -p(3) -
boolean atoms, e.g.,
not #true -
comparison atoms, e.g.,
not X=1,not 0<=X<=10
Safety of Variables
Understanding how atoms and literals function is essential, but it is equally important to ensure that variables within rules are used safely.
Variables in rules must be safe, meaning their possible values are restricted by the rule’s body. Safety is ensured in the following cases:
-
Variables in positive symbolic literals provide safe occurrences, except if nested in complex arithmetic expressions:
-
Safe Examples:
q(X) :- p(X).,q(X) :- p(f(X-1)).,q(X) :- p(f(2*X-1)). -
Unsafe Examples:
q(X) :- p(X*X).,q(X) :- p(|X|).
-
-
Variables in acyclic assignments or variables with lower and upper integer bounds:
-
Safe Examples:
p(X) :- X=a.,p(X) :- f(X)=f(1).,p(X,Y) :- 1<X<Y<4. -
Unsafe Examples:
p(X) :- X>1.,p(X) :- X*X=2.,p(X) :- X=Y, Y=X.
-
|
Pools in Atoms
Pools can also be used within atoms to succinctly represent multiple related atoms in a single expression. When a pool appears in an atom, it is expanded into several atoms according to the terms in the pool. The interpretation of these atoms depends on whether the pool occurs in the head or body of a rule:
-
In heads, all resulting atoms are included together (conjunctively),
-
In bodies, at least one must hold (disjunctively).
This mechanism enables more compact and expressive logic programs:
%%% OPTIONS: 0
p(1;2;3).
q(X) :- X=1..3.
Observe how undefined operations leading to empty pools in heads/bodies essentially discard rule instances:
%%% OPTIONS: 0
p(a-1).
:- q(a-1).
|
The following example demonstrates symbolic literals including classical and default negation:
%%% OPTIONS: 0
p(1;2).
{ -p(3); p(3) }.
not_p(3) :- not p(3).
not_not_p(3) :- not not p(3).
|
The following example demonstrates boolean literals:
a :- #true.
b :- not #false.
|
The following example demonstrates comparison literals:
p(X) :- X=1.
p(X) :- f(X-1)=Y, Y=f(1).
p(X) :- 3<=X<=4.
p(X,Y) :- 5<=X<Y+1<8.
|
Advanced Atoms and Literals
With the fundamentals of atoms and variable safety established, we can explore more advanced constructs that enhance the expressive power of logic programs, such as aggregates and conditional literals.
Body Aggregates
Body aggregates allow us to express conditions over collections of literals in rule bodies, such as counting, summing, or combining values and comparing the result to a bound.
A body aggregate consists of an aggregate function applied to a set of elements, optionally bounded by guards on the left and/or right. The general form is:
term relation function { element; ... } relation term
-
functionis one of:#count,#min,#max,#sum,#sum+ -
relationis a comparison operator:=,!=,<,<=,>,>= -
relationcan be omitted in which case it defaults to>= -
Left/right guards composed of term and relation are optional
Each body aggregate element has the form:
term, ..., term: literal, ..., literal
-
The terms form a tuple (the value(s) contributed by the element)
-
The literals are the condition for including the element
-
The colon can be omitted if the condition is empty.
The semantics of aggregates are as follows:
-
Collect the set of all tuples whose conditions are satisfied
-
Apply the aggregate function to these tuples
-
An aggregate is satisfied if the obtained value applied to all guards holds true
Aggregate functions:
-
#count: the number of tuples whose conditions are true -
#min/#max: the smallest/largest value among the first terms of the tuples -
#sum: the sum of the first term of each tuple (if integer) -
#sum+: like sum but ignores negative integers
A special case is the set body aggregate, which uses a literal instead of a tuple and counts the number of true literals:
term relation { element; ... } relation term
Each set body aggregate element has the form:
literal: literal, ..., literal
This form counts the number of literals on the left of the colon whose conditions on the right are true, and compares the count to the guard(s).
Both forms of aggregates can be default-negated with not or not not.
Safety of Variables in Aggregates
Variables that appear only within aggregate elements are considered local to the aggregate. These local variables do not create additional rule instances but instead generate instances of the aggregate element itself. To ensure correctness, every local variable must be safe within its aggregate element. The mechanism is similar to literals in rule bodies. Aggregates do not provide safe occurrences for variables that are not local.
|
Pools in Aggregates
Pools can be used in several places within aggregates, and their expansion follows the same principles as in rule bodies and heads:
-
Pools in the conditions (right of the colon) of aggregate elements are expanded disjunctively, just like literals in rule bodies.
-
Pools on the left side of the colon (the tuple or literal part) contribute multiple tuples or literals to the aggregate, one for each element of the pool.
-
Pools in guards (the terms compared to the aggregate result) are also expanded disjunctively, like other literals in rule bodies.
|
The following example generates a set of candidates p(1) to p(5) and uses
body aggergates to impose constraints on the number of selected candidates and
their sum:
%%% OPTIONS: 0
{ p(1..5) }.
:- not #count { X: p(X) } >= 2.
:- { p(X) } > 2.
:- not 8 <= #sum { X: p(X) } <= 10.
The aggregates ensure that at least two candidates are selected, no more than two are selected, and the sum of selected candidates is between 8 and 10.
|
The following example illustrates the set semantics of aggregates:
%%% OPTIONS: 0
p(1..3).
q(2..5).
c(S) :- S = #count { X,a: p(X); X,b: q(X); X: p(X); X: q(X) }.
s(S) :- S = #sum { X,a: p(X); X,b: q(X); X: p(X); X: q(X) }.
Observe how the aggregates count/sum the tuples 1,a, 2,a, 3,a from p(X)
and 2,b, 3,b, 4,b, 5,b from q(X), as well as the single terms 1,
2, 3, 4, 5 provided by both predicates.
|
Head Aggregates
Head aggregates allow us to express conditions over collections of literals in rule bodies, such as counting, summing, or combining values and comparing the result to a bound.
-
Derive atoms based on collections of literals
A head aggregate consists of an aggregate function applied to a set of elements, optionally bounded by guards on the left and/or right. The general form is:
term relation function { element; ... } relation term
Except for the elements, a head aggregate has the same structure as a body aggregate:
term, ..., term: literal: literal, ..., literal
-
The element has an additional literal between the tuple and condition
The semantics of aggregates are as follows:
-
Collect the set of all tuples whose literals and conditions are satisfied
-
Apply the aggregate function to these tuples
-
An aggregate is satisfied if the obtained value applied to all guards holds true
-
The aggregate derives all atoms appearing after the tuples of the satisfied elements
A special case is the set head aggregate, which uses a literal instead of a tuple and counts the number of true literals, which have the same form as body set aggregates.
Unlike set body aggregates, head set aggregates derive all atoms of satisfied elements.
Safety of Variables in Aggregates
Safety of variables in head aggregates is similar to body aggregates. However, atoms appreaing before the condition do not provide safe occurrences for variables.
|
Pools in Aggregates
Pools can be used as in body aggregates, and their expansion follows a similar scheme except that pools in guards are expanded conjunctively, like other literals in rule heads.
The following example generates latin squares via atoms p(X,Y) using head
aggregates:
%%% OPTIONS: 0
1 { p(X,1..3) } 1 :- X=1..3.
#count { X: p(X,Y): X=1..3 } = 1 :- Y=1..3.
The aggregates ensure that exactly one atom p(X,Y) per row X and column
Y is chosen.
|
Conditional Literals
Conditional literals can be used in rule bodies to concisely express that a set of literals should be selected based on certain conditions, all of which must be satisfied simultaneously.
A conditional literal has the form:
literal : literal, ..., literal
-
The literal before the colon is the conclusion of the conditional literal
-
The literals after the colon form the condition
-
To avoid ambiguity, conditional literals in rule bodies are separated by
;
The semantics are as follows:
-
Variables that appear only in a conditional literal are local to it; they do not create additional rule instances but only instances of the conditional literal itself.
-
An instance is satisfied, whenever the literal before the colon is satisfied, or one of the literals after the colon is not satisfied. (An instance is an implication: if the condition holds, then the conclusion must hold as well.)
Safety of Variables in Conditional Literals
Safety of variables in conditional literals follows similar principles as for body aggregates:
-
Literals after the colon provide safe occurrences for local variables
-
The literal before the colon does not provide safe occurrences for local variables
-
Local variables must be safely restricted by the condition (literals after the colon)
-
Non-local variables must be made safe outside the conditional literal
Pools in Conditional Literals
Pools can be used both before and after the colon in conditional literals, and their expansion follows these principles:
-
Pools before the colon are expanded conjunctively: all resulting literals must hold.
-
Pools after the colon are expanded disjunctively: at least one must hold.
|
The following example demonstrates conditional literals:
%%% OPTIONS: 0
{ p(1..3) }.
none :- #false: p(1..3).
all :- p(1..3): #true.
:- not all, not none.
The conditional literals ensure that either all or none of the atoms p(1),
p(2), and p(3) are selected.
|
Disjunctions
Disjunctions in rule heads allow us to express that at least one of several alternatives must be true whenever the body holds. This construct is more general than choice rules and is particularly useful for advanced modeling tasks.
A disjunction has the form:
element; ...; element
Each element is either a literal or a conditional element of the form:
literal : literal, ..., literal
Elements can also be separated by | or ,. When using conditional elements,
they must be separated by ; or | to avoid ambiguity.
The semantics of disjunctions are as follows:
-
Variables that occur only in the condition part of a conditional element are local to that element and define additional instances of the element itself.
-
A conditional element is satisfied if all its literals (the head and the condition) are true.
-
For each rule instance, at least one of the head elements must be satisfied if the body holds.
-
The rule can dervive literals (excluding conditions) subject to minimization of derivations.
-
Pools in the conditional elements are expanded disjunctively; all other pools are expanded conjunctively.
Variable safety:
-
Literals in the condition part of a conditional element provide safe occurrences for local variables.
-
All other variables must be made safe outside the disjunction.
The following example demonstrates a disjunction over two literals:
%%% OPTIONS: 0
d(1..2).
p(X); np(X) :- d(X).
For each d(X), either p(X) or np(X) is derived. This is similar to a
choice rule { p(X) } :- d(X)., but here the negation is made explicit via the
atom np(X).
Disjunctions can also be written using default negation:
%%% OPTIONS: 0
d(1..2).
p(X); not p(X) :- d(X).
This is equivalent to the choice rule { p(X) } :- d(X)..
Disjunctions can use conditional elements to generate arbitrary-length disjunctions:
%%% OPTIONS: 0
d(1..6).
p(X) : d(X).
This program has six answer sets, each containing exactly one of the atoms
p(1) to p(6). The disjunction is equivalent to p(1); p(2); p(3); p(4);
p(5); p(6).
In the variable-free case, it is often possible to shift conditions into the body of a rule. For example, the following two programs are equivalent:
%%% OPTIONS: 0
a | b.
c : a | d : b.
%%% OPTIONS: 0
a | b.
:- not a, not b.
c :- a, not b.
d :- not a, b.
c | d :- a, b.
|
Theory Atoms
Theory atoms provide a way to embed custom theories into clingo programs. While clingo offers syntactic support for theory atoms, their semantics are defined by external theory solvers.
A theory operator is a non-empty sequence of symbols from !<⇒+-*/\?&|.:;~^
without spaces or not. The symbols : and ; must be combined with other
symbols.
A theory term can be one of the following:
-
a variable, e.g.,
X -
a number, e.g.,
124 -
a stringo or format string, e.g.,
"abc"orf"abc{X}" -
the special tokens
#infor#sup -
an identifier applied to theory terms, e.g.,
f(t1,t2) -
a tuple:
(t1, …, tn)(with the same rules as for term tuples regarding trailing commas and single-element tuples) -
a list:
[t1, …, tn] -
a set:
{t1, …, tn} -
an expression using theory operators:
expr … expr-
each expressions has form
op … op termwhere each op is a theory operator and each term is a theory term -
all but the first expression must be preceded by at least one theory operator
-
example:
-1+2*3
-
A theory atom has the form:
&name { element; …; element } op term
-
nameis a term that serves as the name of the theory atom. -
op termis an optional guard consisting of a theory operator and a theory term. -
The braced part can be omitted if the theory atom has no elements.
Each element inside the braces has the form:
term, …, term : literal, …, literal
-
Each
termis a theory term together forming atuple. -
The literals form the condition of the element.
-
The condition (after the colon) can be empty, in which case the colon can be omitted.
Variables that occur only in theory atoms are local and must be made safe by literals in the condition part of elements. Local variables define a set of instances of theory elements. Pools in conditions are expanded disjunctively. Pools in names expand conjunctively in the head and disjunctively in the body of rules. The semantics of theory atoms are defined by external theory solvers.
The following example demonstrates theory atoms:
%%% OPTIONS: --mode=parse
p(a,b) :- &here.
p(b,c) :- &there.
&diff { X-Y: p(X,Y) } <= 2.
h :- &sum { X: X=1..3 } >= 3.
&minimize{ X::Y: p(X,Y) }.
The example is set up to just parse and print the program without actual grounding. To actually ground programs with theory atoms, a theory specification is needed (see Theory Directives). To solve them, a theory solver must be implemented using clingo's API.
Statements
Finally, we discuss the various statements that can be used in clingo programs, which provide additional control and flexibility.
Comments
Comments allow us to include explanatory notes within our clingo programs without changing their behavior. clingo two types of comments: line comments and block comments.
Line comments start with % and continue to the end of the line:
% abc
% def
Block comments start with %* and end with *%, and can span multiple lines
with limited nesting support:
%*
abc
%*
def
*%
ghi
*%
|
Rules
Rules are the primary constructs in clingo programs that define relationships between atoms. A rule has the general form:
head :- literal; ...; literal.
-
headis a head literal (including basic literals, head aggregates disjunctions, and theory atoms). -
literal; …; literalare body literals (including basic literals, body aggregates, conditional literals, and theory atoms). -
Body literals can be separted by
,or;. Conditional literals must be separated by;.
A rule is satisfied if the head literal is true or at least one body literal is false. Rules derive head literals subject to minimization of cyclic derivations.
%%% OPTIONS: 0
a. % a fact
{b}. % a choice rule
c :- a; b, not c. % a normal rule
c | b. % a disjunctive rule
|
Show Directives
Show directives control the output of answer sets by specifying which atoms to show.
Show directives have the following forms:
#show. #show name/arity. [flag] #show term : body.
Their semantics are as follows:
-
The first variant indicates that atoms not explicitly shown are hidden.
-
The second variant shows all atoms with the specified name and arity if flag is
trueor hides them if flag isfalse. The flag is optional and defaults totrue. -
The third variant shows all terms whose bodies are satisfied. The body shares the same syntax/semantics as rule bodies. Pools in terms expand to multiple show statements.
%%% OPTIONS: 0
{a}.
b.
#show.
#show b/0.
#show c: a.
|
Const Directives
Const directives allow us to define constants that can be used throughout a logic program.
Const directives have the following form:
#const name = term. [type]
-
nameis the name of the constant -
termis a term that is to be assigned to the constant -
typeis an optional type that can be eitherdefaultoroverridedefaulting todefault-
The syntax of terms is restricted: variables and pools are not allowed.
-
%% OPTIONS: 0
#const n = 3.
p(1..n).
|
Projection Directives
Projection directives specify relevant atoms in solutions. When enumerating answer sets, solutions are considered equivalent if they agree on the projected atoms. Only one representative of each equivalence class is included in the output.
Projection directives have the following form:
#project name/arity.
Here, name is the name of the atom and arity is its arity.
%%% OPTIONS: 0 --project
#project p/1.
% #show p/1. % uncomment to only show projected atoms
1 {p(1..3)} 1.
1 {q(1..3)} 1.
|
Weak Constraints
Weak constraints allow us to express preferences among answer sets by assigning penalties to certain conditions. They are used to guide the solver toward optimal solutions according to specified criteria.
A weak constraint has the following form:
:~ body. [weight@level, term, ..., term]
-
bodyhas the same form as rule bodies. -
weight,level, and termsterm, …, termare terms. -
levelis optional and defaults to0.
The semantics of weak constraints are as follows:
-
Whenever the body is satisfied, the weak constraint incurs a penalty of
weightat optimizationlevel. -
Penalties are considered once for each unique tuple (
weight,level,term, …,term). -
The solver seeks answer sets that minimize the total penalty, considering higher levels as more important.
-
weightandlevelmust evaluate to integers.
Variable safety:
-
Variables in the body must be safe, as in integrity constraints.
-
Variables in the annotation (
weight,level,term, …,term) must also be made safe by the body.
The following example demonstrates weak constraints in a graph coloring problem:
%%% OPTIONS: 0 --opt-mode=optN -q1
color(red;green;blue).
node(a;b;c;d).
edge(U,V) :- node(U), node(V), U < V.
1 { assign(N,C): color(C) } 1 :- node(N).
:~ edge(U,V), assign(V,C), assign(U,C). [1@2,U,V]
:~ assign(U,C), assign(V,D), V < U, C < D. [1@1,U,V]
#show assign/2.
The first weak constraint penalizes edges whose endpoints have the same color (level 2; most important). The second weak constraint breaks symmetries by preferring to assign smaller colors to smaller nodes (level 1; less important).
|
Optimization Directives
Optimization directives provide an alternative way to express optimization criteria in logic programs.
Optimization directives have one of the following forms:
#minimize { element; ...; element }.
#maximize { element; ...; element }.
Elements have the form:
weight@level, term, ..., term : literal, ..., literal
Each element in a minimize directive is equivalent to a weak constraint of form:
:~ literal, ..., literal. [weight@level, term, ..., term]
Each element in a maximize directive is equivalent to a weak constraint of form:
:~ literal, ..., literal. [-weight@level, term, ..., term]
|
Program and Parts Directives
Program directives allow us to structure logic programs into named parametrized sections. They are used for multi-shot solving, where different parts of a program can be grounded and solved incrementally. Or to organize large programs into composable programs parts.
Part directives have form:
#parts part, ..., part. [type]
-
typeis an optional type that can be eitherdefaultoroverridedefaulting todefault.
Each part has the form:
name(term, ..., term)
-
nameis the name of the program part and follows identifier syntax. -
termis a term without variables or pools.
#parts base, inject(4).
q(1..3).
q(X) :- p(X).
#program inject(n).
p(n).
|
External Directives
External directives allow you to declare atoms as external, meaning their truth values can be controlled from outside the logic program. This feature is especially useful for multi-shot solving and for handling dynamic problem instances.
An external directive has the following form:
#external atom : body. [flag]
-
atomis a basic atom. -
bodyis a rule body, following the same syntax and semantics as in rules; the colon can be omitted if the body is empty. -
flagis an optional term that must evaluate to one oftrue,false,free, orrelease(default:false).
The semantics are as follows:
-
The directive is grounded like a rule; after grounding, the body is discarded and the atom is declared external.
-
The initial truth value of the external atom is determined by the flag, but can be changed later via the API.
Variable safety:
-
Variables in the atom and body must follow the same safety rules as in rules.
-
Variables in the flag must be made safe by the body.
The following example demonstrates external directives:
%%% OPTIONS: 0
#external p(X) : X=1..3. [true]
#external p(4). [free]
#external p(5). [false]
#external p(6).
|
Include Directives
Include directives enable modularization by allowing you to incorporate external files or built-in modules into your logic programs. This helps organize large programs and promotes code reuse.
There are two types of include directives:
-
Standard includes, which incorporate user-defined files.
-
Built-in includes, which provide access to predefined modules.
The syntax is as follows:
#include "path". #include <module>.
-
pathspecifies the file to be included; it can be absolute or relative to the current file or working directory. -
moduleis the name of a built-in module provided by clingo; currently, onlyincmodeis supported.
When an include directive is encountered, the specified file or module is grounded just like a regular file passed to clingo on the command line.
The incremental mode module provides simple support for multi-shot solving, particularly useful for planning problems. Program parts are grounded and solved incrementally based on time steps until a solution is found.
#include <incmode>.
#program base.
p(0).
#program step(t).
p(t) :- p(t-1).
#program check(t).
:- query(t), not p(3).
The grounding and solving of the above example proceeds as follows:
-
baseandcheck(0)are grounded and solved: unsatisfiable -
step(1)andcheck(1)are grounded and solved: unsatisfiable -
step(2)andcheck(1)are grounded and solved: unsatisfiable -
step(3)andcheck(3)are grounded and solved: satisfiable
|
Edge Directives
Edge directives provide a concise way to construct directed graphs within logic programs by conditionally including edges. Any answer set that induces a cyclic graph is automatically discarded.
The general form of an edge directive is:
#edge (term, term; ...; term, term) : body.
-
Each
term, termpair specifies an edge from the first node to the second node. -
bodyis a rule body, following the same syntax and semantics as in rules; the colon can be omitted if the body is empty.
Variable safety:
-
Variables in the terms must be made safe by the body.
-
The body follows the same safety rules as rule bodies.
The following program selects at least two edges from an example graph and ensures that the resulting graph is acyclic using edge directives:
%%% OPTIONS: 0
edge(a,b).
edge(b,c).
edge(c,a).
2 { pick(X,Y) : edge(Y,X) }.
#edge (X,Y) : pick(X,Y).
|
Heuristic Directives
Heuristic directives allow you to influence the solver’s search strategy by specifying preferences for certain atoms to be true or false during solving. This can guide the solver toward more desirable solutions or improve performance on specific problems.
A heuristic directive has the following form:
#heuristic atom : body. [weight@priority, modifier]
-
atomis a basic atom. -
bodyis a rule body, following the same syntax and semantics as in rules; the colon can be omitted if the body is empty. -
weightandpriorityare terms that evaluate to integers;priorityis optional and defaults to0. -
modifieris one oftrue,false,level,sign,init, orfactor.
Semantics:
-
A heuristic modification is applied whenever the body is satisfied.
-
The
prioritydetermines the importance of the heuristic modification; higher priorities take precedence. -
Modifiers:
-
level: Sets the decision level of the atom toweight. Atoms with the highest level are considered first for branching. -
sign: Sets the preferred truth value of the atom to true (weight > 0), false (weight < 0), or default (weight = 0). -
true/false: Shorthand for setting the sign preference to 1 or -1, respectively, and the level to the value ofweight. -
init: Increases the activity score of the atom byweight, making it more likely to be selected early in the search. The score decays over time and is increased only once. -
factor: Multiplies the current activity score of the atom byweight, boosting its importance throughout solving.
-
Variable safety:
-
atomandbodymust follow the same safety rules as in rules. -
Variables in
weight,priority, andmodifiermust be made safe by the body.
The following example demonstrates heuristic directives:
%%% OPTIONS: --heuristic domain
{p(1..3)}.
{q(1..3)}.
#heuristic p(X). [1, true]
#heuristic q(X). [1, false]
The example is set up to compute only one model. The heuristic directives
specify that atoms over predicate p/1 should be made true and atoms over
predicate q/1 should be made false whenever possible.
|
Script Directives and External Functions
Script directives allow you to embed scripts written in supported languages (currently only Python) directly into your clingo programs. Scripts can be used to define external functions that are callable from the logic program, or to manipulate the solving process via the clingo API.
The general form of a script directive is:
#script (language) code #end.
-
languagespecifies the scripting language (currently onlypythonis supported). -
codeis the script code; it must not contain the#end.directive.
External functions defined in the script can be called from the logic program
by prefixing function names with @.
The following example demonstrates how to define and use external functions in Python:
#script (python)
from clingo.symbol import Number
def succ(lib, n):
return Number(lib, n.number + 1)
def rng(lib, a, b):
return [Number(lib, i) for i in range(a.number, b.number + 1)]
#end.
p(@succ(3)).
q(X) :- X=@rng(1,3).
|
Theory Directives
Theory directives allow you to define custom theories that can be used within logic programs. Theories are collections of theory atoms with specific syntax and semantics, which are interpreted by external theory solvers via the clingo API.
A theory directive has the following form:
#theory name {
term_definition;
...
term_definition;
atom_definition;
...
atom_definition
}.
A term_definition specifies the operators and their properties for theory terms:
name {
operator_definition;
...
operator_definition
}.
Each operator_definition has the form:
theory_operator : precedence, arity, associativity
-
theory_operatoris a sequence of symbols (see Theory Atoms for allowed characters). -
precedenceis a non-negative integer. -
arityis eitherunaryorbinary. -
associativityis eitherleftorright(only for binary operators).
An atom_definition describes the allowed forms of theory atoms:
&name/arity: term, {relation,...,relation}, term, type.
&name/arity: term, type.
-
The first variant defines a theory atom with optional guards:
-
The first
termspecifies the permissible terms within the theory atom. -
The set
{relation,…,relation}and the secondtermspecify the permissible guards. -
The
typedetermines where the theory atom can appear:head,body,any, ordirective.-
head: only in rule heads -
body: only in rule bodies -
any: in both heads and bodies -
directive: only in the head of a rule with an empty body
-
-
-
The second variant defines a theory atom without guards, following the same rules for the remaining parts.
The theory directive thus specifies both the syntax (allowed operators, terms, and atoms) and the placement of theory atoms in rules. The actual semantics are provided by an external theory solver, which must be implemented using the clingo API.
The following example defines a simple theory for constraint satisfaction problems:
%%% OPTIONS: --convert=text
#theory csp {
term {
+ : 1, binary, left;
- : 1, binary, left;
* : 2, binary, left;
/ : 2, binary, left
};
&sum/0: term, {<,<=,>,>=,=}, term, any;
&minimize/0: term, directive
}.
{p(1..3)}.
&sum { 1-2+3*var(X) } >= X :- p(X).
:- &sum { var(X): p(X) } < 3.
&minimize { var(X): p(X) }.
|