ASP-04 | Numbers and Math
Introducing integers and arithmetic operations into ASP, expanding our logical toolset beyond simple atoms to handle numerical computations and comparisons.Photo Credit: Rob Grzywinski
Now things start to get exciting!
Up to this point we have used only string-based atoms. We're going to venture in to the realm of integers and math! Please note that only integers are supported. There are no floating-point numbers in ASP. This limitation exists because ASP is designed for exact reasoning and finite domains. Floating point numbers, with their inherent imprecision and infinite possible values between any two numbers, would make it impossible to guarantee the solver finds all stable models in finite time.
Facts
Terms in predicates can include integers:index(1) .
index(2) .
index(3) .
Integers can be used with pooling as well:index(1 ; 2 ; 3) .
We have seen examples before that include multiple instances of pooling. This example describes a 2x2 gridsquare((1 ; 2), (1 ; 2)) .
Don't forget the parenthesis otherwise you won't get the desired results!square(1 ; 2 , 1 ; 2) .
Remember that "," binds before ";" resulting in {square(1) square(2)square(2,1)}
(which also shows that you can create predicates with different arity within a single atom).Intervals
Intervals are another available shorthand:index(1..3) .
This is equivalent to:index(1 ; 2 ; 3) .
Intervals are inclusive of their bounds (1..1 results in 1). The answer set for (1), (2) and (5) are all {index(1) index(2) index(3)}
. Note that intervals can only be applied to integers. a..c returns a warning that the interval is undefined.Intervals don't suffer from the same precedence problem and can be used without parenthesis:square(1..2, 1..2) .
(3) and (7) produce the same answer set .Mixing intervals and constants:rectangle(1..2, 2) .
results in .Negative integers may be used as well.index(-3..3) .
results in . (Please note that atoms within an answer set are ordered lexicographically not numerically!)Inverted intervals:index(3..-3) .
result in the empty set ().
Operators
Arithmetic Operators
The following arithmetic operators are available with their expected precedence:+: Addition-: Subtraction*: Multiplication**: Exponentiation/: Integer division\: Remainder| |: Absolute value
(Bitwise operators are also available but are rarely used.)They can be used in facts:addition(1 + 1) .
subtraction(3 - 7) .
multiplication(2 * 6) .
exponentiation(3 ** 2) .
division(7 / 3) .
remainder(7 \ 3) .
absolute_value(|-15|) .
combination(4 * 3 + 3 / 5) .
{absolute_value(15)addition(2)combination(12)division(2)exponentiation(9)multiplication(12)remainder(1)subtraction(-4)}
These arithmetic operators can be applied in any term such as within intervals:p((-2-1) .. (2*3-4)) .
{p(-1) p(-2) p(-3) p(0) p(1) p(2)}
Comparison Operators
The following comparison operators are available=: Equality!=: Inequality<: Less than<=: Less than or equal to>: Greater than>=: Greater than or equal to
They can be used in rules:equal ← 1 = 1 .
not_equal1 ← 2 = 1 .
not_equal2 ← 2 != 1 .
not_equal3 ← 2 != 2 .
less_than1 ← 3 < 1 + 1 .
less_than2 ← 4 + 5 < 5 * 4 .
greater_than1 ← 3 > 1 + 1 .
greater_than2 ← 4 + 5 > 5 * 4 .
{equalgreater_than1less_than2not_equal2}
(Remember that rules where the body is replaced with a truth value of ⊥ are not found in the answer set.)ASP defines a total order for all (variable-free and without arithmetic operations) atoms so that it is possible (though not common) to compare atoms and numbers:greater_than ← a > 1 .
less_than ← a < 1 .
Remember that a is not a variable; it is an atom (and it doesn't need to exist in the head of a rule). It is more common to compare atoms:greater_than ← b > a .
less_than ← b < a .
(See [Rules Part II] for an example.)Equality vs Belongs To
Recall from "Variables | Sets" that the "=" operator read as "belongs to". So how is "=" able to be both "equals" and "belongs to"? The answer can be found in the "Logic Programming Rules! | Rules whose Body Evaluates to false" section. Look at the following cases and think about what you would expect the answer set to contain:example(1) ← 2 = 2 .
example(2) ← 2 = (1 ; 2 ; 3) .
example(3) ← 2 = 1..3 .
All three atoms are in the answer set ({example(1) example(2) example(3)}
)! Let's expand the pooling and intervals for clarity and note any rules whose body evaluates to false since they do not contribute:example(1) ← 2 = 2 .
example(2) ← 2 = 1 . % FALSE
example(2) ← 2 = 2 .
example(2) ← 2 = 3 . % FALSE
example(3) ← 2 = 1 . % FALSE
example(3) ← 2 = 2 .
example(3) ← 2 = 3 . % FALSE
All forms are equivalent!The same statements can be made for all of the arithmetic operators:example(4) ← 3 < 1..4 .
example(5) ← 3 > 1..4 .
(Expand the intervals and cross out any rules whose body evaluates to ⊥ to understand the results.)And intervals as well!example(6) ← 1..3 < 1..4 .
example(7) ← 1..3 = 1..4 .
Rules and Variables
Combining variables and rules increases the expressivity of rules.p(X, X*X, X+1) ← X = 1..3 .
In this context the "=" operator should be read as "belongs to". Expanding the interval makes it clear what the answer set contains:p(X, X*X, X+1) ← X = 1 .
p(X, X*X, X+1) ← X = 2 .
p(X, X*X, X+1) ← X = 3 .
Arithmetic operators can be used with intervals as well on both the left- and right-hand sides of the "=":p(X) ← X + 3 = 1..3 .
q(X) ← X = (1..3) - 3 .
Notice that the parenthesis are necessary in the second rule since "-" binds before "..".Intervals can be combined with other intervals:p(X) ← X = (1..3) * (3..6) .
{p(10) p(12) p(15) p(18) p(3) p(4) p(5) p(6) p(8) p(9)}
Multiple variables with intervals can be used:p(X, Y, X + Y) ← X = 1..3, Y = 1..2 .
And intervals can be used in the head of the rule as well:p(X, 1..2) ← X = 1..3 .
Solver Limitations
The solver is designed to support finite answer sets. If it gets into a case where it thinks that it will generate infinite results then it will stop and report an "unsafe" error.p(X) ← X > 3 .
(Hover over the error above to see: <Error: -:1:1-16: error: unsafe variables in: p(X):-[#inc_base];X>3. -:1:3-4: note: 'X' is unsafe>)There are limitations in which the solver cannot detect that it would not produce infinite resultsp(X) ← X > 3, X < 9 .
{p(4) p(5) p(6) p(7) p(8)}
(Note that prior versions of the solver would return: <Error: -:1:1-23: error: unsafe variables in: p(X):-[#inc_base];X<9;X>3. -:1:3-4: note: 'X' is unsafe>. This is no longer the case!). Future versions of the solver will be better equipped to handle cases like this. In case such as this, it is best to use an explicit interval to ensure that the solver understands that there is a finite rangep(X) ← X = 4..8 .
{p(4) p(5) p(6) p(7) p(8)}