Relational operators
CQL has 6 relational operators:relation | meaning |
---|---|
< | less than |
≤ | less than or equal to |
≥ | greater than or equal to |
> | greater than |
≺ | ancestor of |
≼ | ancestor of or equal to |
≽ | descendant of or equal to |
≽ | descendant of or equal to |
== | 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 }
The four relational operators
≺, ≼, ≻, ≽
only allow position arguments. These four filters are discussed in more detail here: ancestor/descendant relation operators.
matching the position
Each of these relational operators is its own filter. For example, the CQL expressionpower A<power ais 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:
==
and both operands are sets, then the filter is treated specially.
≠
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:#△
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:#△
will be true only if the following two conditions are satisfied:
- the current position is not the initial position
- 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:#△ 5<parent:#△ 5>parent:#△
However,
5 != parent:#△
always matches the initial position, because it is an abbreviation for
not {5 == parent:#△}
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,
△==3
means the same thing as
{#△}==3
and is true when the current position has exactly 3 white pieces.
Similarly,
△→♚>1is converted into
#{△→♚}>1and matches the current position when the black king is in double check.
Comparing positions with <, <=, >, and >=
If each operand of the two operands of a binary comparison operator is a position filter, the associated comparison is performed on the positionid of the operands. That is, ifX
and Y
are positions, then
is true exactly when theX
<Y
positionid
of X
is smaller than the positionid
of Y
.
{find check}<find ――=♘is equivalent to:
{find check} : positionid<{find ――=♘} : positionidIn the above expression, the value of the
find check
filter isthe next position that is a check.
The value of the find ――=♘
filter is the next position from which there is a knight underpromotion.
When these two positions are compared, their numeric positionid values are compared
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 ――=♘} : positionid
is the positionid of the next position from which there is 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==a-h1-8matches 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==64or, 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 ≤ (#♙<7)
That is because, if the number of white pawns is ≥ 7
, then
the #♙<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 #♙<7
will match
and will have value equal to #♙
.
In this case, the whole filter will match
if 4 ≤ #♙
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 ≤ ♙<7
Such ternary relational operator notation is common in mathematics, but many programming languages do not support the notation.
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<3is parsed as
{abs x}<3rather than
abs {x<3}
However, because sort can take a set filter as argument,
sort #△≥10 ≡ sort (#△≥10) ≡ sort △ ≥ 10 ≡ sort (△ ≥ 10)which sorts on the number of white pieces when that number is at least 10. Note that
△ ≥ 10
is converted into (#△) ≥ 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:♕==2 ♛==2 ◭==6Here,
♕==2
is converted (due to conversion of set operands discussed above) into #♕==2
. That is, the filter is true if the number of white queens on the board is equal to 2.
Similarly, ♛==2
is true if the number of black queens on the board is equal to 2.
Finally, ◭==6
is true if the total number of white (A
) and black (a
) pieces is equal to 6. If so, the material must be ♔♕♕♚♛♛
.
This file finds the following position:
(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.