Relational operators

CQL has 6 relational operators:
relationmeaning
<less than
<=less than or equal to
>= greater than or equal to
>greater than
== equal to
!= not equal to

The != filter is defined as an abbreviation for applying the not filter to the filter that results from replacing the != with ==:

left != right

not { left == right }

Note: Relational filters are sometimes called comparison filters are comparison operators or relational operators. The two arguments to a relational operator are sometimes called operands.

matching the position

Each of these relational operators is its own filter. For example, the CQL expression
power A<power a
is a < filter whose two arguments are the filters power A and power a.

Generally, if either or both of the two operands to a relational filter does not match the current position, then neither does the relational filter, except in two cases:

• If the filter is == and both operands are sets, then the filter is treated specially.
• The != filter is treated as an abbreviation for not ... == ...

For example, consider the following filter, which is equal to the number of white pieces in the previous position:

parent:#A

If the current position is the initial position, then this parent filter would not match the position (since the initial position has not parent). Suppose the current position is the initial position.

5==parent:#A

will be true only if the following two conditions are satisfied:

1. the current position is not the initial position
2. the previous position has exactly 5 white pieces in it.

Thus, if the current position is the initial position, each of the following three filters are always false (never match):

5 == parent:#A
5<parent:#A
5>parent:#A

However,

5 != parent:#A
always matches the initial position, because it is an abbreviation for
not {5 == parent:#A}

Conversions of set operands to numbers

If exactly one operand of a relation operator is a set filter and the other operand is a numeric filter, then the set represented by the set filter is converted into its cardinality.

Thus,

A==3
means the same thing as
{#A}==3
and is true when the current position has exactly 3 white pieces.

Similarly,

A attacks k>1
is converted into
#{A attacks k}>1
and matches the current position when the black king is in double check.

Conversion of position operands to numbers

If each operand of the two operands of a binary comparison operator is a position filter, then each is replaced by its positionid:
{find check}<find move promote N
is equivalent to:
<
{find check} : positionid<{find move promote N} : positionid
In the above expression, the value of the find check filter isthe next position that is a check.

The value of the find move promote N filter is the next position that is a knight underpromotion.

When these two positions are compared, they are converted into their numeric positionid values. The positionid filter has as value the position id of the current position. Thus, {find check} : positionid gives the positionid of the position of the next check, using the : operator to evaluate positionid using another current position. Likewise, {find move promote N} : positionid is the positionid of the next knight underpromotion.

Conversions of position operands are most commonly used in the body of the echo filter. Typically, an echo filter might begin something like this:

echo (source target) {
source<target
...
}

This idiom can be used to ensure that the target position is a descendant of the source position (if variations is not set); or simply to make sure that the same pair of positions is only evaluated once in the body of the echo.

comparing set filters using ==

If both operands of the == operator are set filters, then the operands are compared as sets: the filter matches only if the corresponding sets are identical. Likewise, if both operands of the != filter are sets, then filter matches only if the corresponding sets are not identical. These rules apply even if the sets are empty.

For example, if x is a set variable, then

x==.
matches a position exactly when x is the all 64 squares. This expression has the same effect as the following, which is true if x contains 64 squares:
#x==64
or, equivalently, by using the conversion of set operands to numbers to
x==64
.

The numeric value of a comparison operator

A comparison operator with numeric arguments is also a numeric filter. If a comparison operator matches the current position, then its value is the value of its first operand in the position. This applies to all the comparison operators except for !=, which has no numeric value by definition. It also does not apply for the numeric operator == when both its arguments are sets (since sets are compared with set equality).

For example, to check if the number of white pawns is between at least 4 and smaller than 7 in a position, we can use

4<=(#P<7)

That is because, if the number of white pawns is >= 7, then the #P<7 filter will not match, so neither neither will the 4<=... filter (because relational filters do not match if one their arguments does not match).

On the other hand, if the number of white pawns is smaller than 7, then #P<7 will match and will have value equal to #P. In this case, the whole filter will match if 4<=#P matches, which is what we want.

In fact, because relational operators are right associative, and because sets compared with numbers are converted to their cardinality, the above filter is equivalent to the terse:

4<=P<7

Such ternary relational operator notation is common in mathematics: CQL is one of the few (only?) languages we are aware of supporting it.

The numeric value of comparison operators is often exploited in echo filters that are sorted. Sometimes we want to sort an echo by the distance between the source and the target:

sort
echo (source target){
...
distance(source target)>= 5}

The value of the body of the echo is equal to distance(source target) whenever that distance is at least 5 (and the other requirements of the echo body also match). If the distance is not at least 5, the body does not match.

When a named filter requires a numeric argument, the filter normally has higher precedence than the binary comparison operators. Thus,

abs x<3
is parsed as
{abs x}<3
rather than
abs {x<3}

However, because sort can take a set filter as argument,

sort #A>= 10

sort (#A>= 10)

sort A>= 10

sort (A>= 10)
which sorts on the number of white pieces when that number is at least 10. Note that A>= 10 is converted into (#A)>= 10 due to the conversion of set operands with relational operators.

Relational operators with string arguments

Relational operators can have string filter arguments. Strings are compared in lexicographic order by the ASCII value of their characters, so that for example

"A">"a"
"Ab">"A"
""<"A"

Relational operators have string values just like the case for for numeric values. Therefore, they can be chained just like for numeric values.

Thus, to check that a character X is lowercase, one could use

"a"<=X<="z"

(or more generally, lowercase X==X)

Examples

Relational operators are used in most of the CQL examples, starting with the simplest example, QQqq.cql, which finds positions with the material of two queens against two queens, and no other pieces:
Q==2
q==2
[Aa]==6
Here, Q==2 is converted (due to conversion of set operands discussed above) into #Q==2. That is, the filter is true if the number of white queens on the board is equal to 2.

Similarly, q==2 is true if the number of black queens on the board is equal to 2.

Finally, [Aa]==6 is true if the total number of white (A) or black (a) pieces is equal to 6. If so, the material must be KQQkqq.

This file finds the following position:

Elkies 1993, after 7. Qfg8! (zugzwang)
(found from CQL file: qqqq.cql)

In the position it is black to move, and because of this, black loses. If the position were white to move, black would draw. This position itself was found by computer; the study is the first ever composed using a six-piece tablebase.