Comparison functions <
≤
=
≥
>
≠
#
In this Jupyter notebook we will go over 6 APL functions, the comparison functions <
≤
=
≥
>
≠
. As the name suggests, we use these functions to compare their arguments.
The comparison functions are dyadic scalar functions. Being dyadic means that they require both a left and a right argument and being scalar means they penetrate into nested arrays all the way down to the simple scalars composing said arrays. These are the names of the six comparison functions:
=
is the Equal To function and≠
is the Not Equal To function;<
is the Less Than function and>
is the Greater Than function;≤
is the Less Than or Equal To function and≥
is the Greater Than or Equal To function;
We start by exploring a bit these six scalar functions giving some brief examples on how to use them. After that, we explore some relationships these functions satisfy among themselves and some tips on simplifying the usage of these functions.
A foreword on logical values in APL#
Depending on what your programming background is (if any) this may come as a surprise to you… but in APL the logical values ― the “things” we use to indicate if an expression is true or false ― are represented by the numbers \(1\) and \(0\).
In languages like Python or Java we have keywords for those but in other languages like C and APL we use \(0\) to represent false and we use \(1\) to represent true. This may seem like a step back if you are used to having true/false
keywords but later on you will be shown that this in fact can be quite handy.
For the purposes of this notebook, it means that if applying one of the comparison functions returns \(1\) then it means the comparison is true and if the function returns \(0\) then the comparison is false.
Equal To#
The Equal To function =
checks if the left and right scalars are the same scalar. This function can be applied to more than just numbers!
1 = 1
1 = 2
1 = 1.0
'u' = 'u'
'a' = 'v'
2 = '2'
0J1 = 0J1
1J3.4 = 1J3.3
We can also aggregate all these previous comparisons into a single statement. We just aggregate the left values into an array and the right values into another array and then compare the two arrays, scalar by scalar:
1 1 1 'u' 'a' 2 0J1 1J3.4 = 1 2 1.0 'u' 'v' '2' 0J1 1J3.3
oneTwoThree ← 12⍴1 2 3
oneTwoThree
Another property we get from the fact that the comparison functions are scalar is that we can have a simple scalar on one of the sides and an array on the other side. To perform the comparison, the scalar is first extended to match the shape of the array and then the two arrays are compared element by element.
oneTwoThree = 1
oneTwoThree = 12⍴1
We can also try to understand what happens when we have different types of nested arrays:
2 = (1 2 3)(2 (1 2))(5 6 2 ¯1)
(2 3 4) = (2 2 2)(2 3 4)(3 4 5)
(1 2 3) = (1 2 3)(2 2⍴⍳4)(3 3 3 5 3)
(1 2 3) = (1 2 3)((2 2 2)(2 3 4)(3 4 5))(3 4 5)
But this breaks down if the two outer arrays don’t have matching lengths and one of them can’t be extended like we saw above.
(1 2) = (1 2 3)(2 3 4)(3 4 5)(4 5 6)
LENGTH ERROR
(1 2)=(1 2 3)(2 3 4)(3 4 5)(4 5 6)
∧
Not Equal To#
The Not Equal To function ≠
checks if the left and right scalars are different from one another and, just like the Equal To function, can be applied to scalars other than numbers.
1 1 1 'u' 'a' 2 0J1 1J3.4 ≠ 1 2 1.0 'u' 'v' '2' 0J1 1J3.3
1 ≠ oneTwoThree
oneTwoThree ≠ ⍳12
Less Than#
The Less Than function <
checks if the left scalar is to the left of the right scalar if the two scalars are seen on the number line.
2 < 1
2 < 2
2 < 3
2 < oneTwoThree
5 < ⍳12
For how many positive integers \(k\) is \(e^k\) below \(1000\)?
+/ (*⍳10) < 1000
This means \(e^7\) should be \(1000\) or greater:
*7
Comparing things other than numbers#
This “less than” notion is a property of numbers, and thus <
doesn’t work on scalars other than numbers. This is also true for Greater Than (>
), Less Than or Equal To (≤
) and Greater Than or Equal To (≥
).
Notice how you cannot run something like 'g' < 'G'
because of a domain error, i.e. <
was not expecting character scalars:
'g' < 'G'
DOMAIN ERROR
'g'<'G'
∧
You can, however, use ⍋
and ⍒
to grade any type of array. This means you can check how the array ('g' 'G')
would be sorted and then compare the sorting indices, for example with
'g' {</⍋⍺⍵} 'G'
Because we got a \(0\) here, this means that in a character array 'g'
would come to the right of 'G'
:
charArray ← 'abcghizywxJHGFDS'
charArray[⍋charArray]
Greater Than#
The Greater Than function >
checks if the left scalar is greater than the right scalar, which on the number line checks if the left scalar is to the right of the right scalar.
2 > 1
2 > 2
2 > 3
2 > oneTwoThree
5 > ⍳12
What is the first integer \(k\) for which \(e^k\) is greater than \(1000\)?
⊃⍸ (*⍳10) > 1000
So \(e^7\) should be greater than \(1000\):
*7
Interchangeability of <
and >
#
The <
and >
functions have a really nice property: ⍺ < ⍵
is exactly the same as ⍵ > ⍺
so you can look for opportunities to change one with the other when changing the order of the expression allows you to remove, for example, a set of parentheses!
Check how the two lines of code above can be simplified a bit by swapping the usages of <
and >
and by swapping their arguments:
+/ (*⍳10) < 1000
+/ 1000 > *⍳10
⊃⍸ (*⍳10) > 1000
⊃⍸ 1000 < *⍳10
This also means you are highly unlikely to ever need to use ⍨
with <
or >
, as dyadic <⍨
simplifies to >
and dyadic >⍨
simplifies to <
.
What if you want to use <⍨
or >⍨
but to call them monadically? ⍵ < ⍵
and ⍵ > ⍵
are always \(0\) so there is also no need to do that!
Less Than or Equal To#
The Less Than or Equal To ≤
function checks if the left scalar is less than or equal to the right argument.
2 ≤ 1
2 ≤ 2
2 ≤ 3
2 ≤ oneTwoThree
The Less Than or Equal To ≤
function can be seen as the logical disjunction of the functions Less Than and Equal To ; in fact, less than or equal to is comprised of (less than <
) (or ∨
) (equal to =
).
2 < oneTwoThree
2 = oneTwoThree
2 (<∨=) oneTwoThree
2 ≤ oneTwoThree
Greater Than or Equal To#
The Greater Than or Equal To ≥
function checks if the left scalar is greater than or equal to the right argument.
2 ≥ 1
2 ≥ 2
2 ≥ 3
2 ≥ oneTwoThree
In a similar fashion to the Less Than or Equal To function, the Greater Than or Equal To function can be broken up in three parts: (greater than >
) (or ∨
) (equal to =
).
2 > oneTwoThree
2 = oneTwoThree
2 (>∨=) oneTwoThree
2 ≥ oneTwoThree
Interchangeability of ≤
and ≥
#
We have in ≤
and ≥
a property just like what we have with <
and >
: ⍺ ≤ ⍵
is exactly the same as ⍵ ≥ ⍺
so, again, you can look for opportunities to change one with the other. Sometimes this means we can simplify an expression by swapping the arguments, for example by dropping a set of parentheses.
From this we also see there is no point in using dyadic ≤⍨
and ≥⍨
. As for the monadic versions of those, notice that ⍵ ≤ ⍵
and ⍵ ≥ ⍵
always return \(1\) so it isn’t meaningful to consider monadic ≤⍨
or ≥⍨
.
Logical opposites#
These six functions form three pairs of logical opposites:
=
is the opposite of≠
and vice versa;<
is the opposite of≥
and vice versa;>
is the opposite of≤
and vice versa.
Equal and Not Equal To are opposite from one another#
If you go back to the beginning, you will notice that the results for the examples with =
are exactly the opposite of the results we get when using ≠
.
This is because the Not Equal To function ≠
is the logical negation of =
, which means that using =
and then negating is the same as using ≠
; it also means that using ≠
and then negating it is the same as using just =
.
By the way, notice the strikethrough over =
that creates ≠
, also mimicking the mathematical notation for \(=\) and \(\neq\).
notUnequal ← ~ 1≠oneTwoThree
notUnequal
equal ← 1 = oneTwoThree
equal
equal ≡ notUnequal ⍝ Check if the arrays are the same
(~oneTwoThree=⍳12) ≡ (oneTwoThree ≠ ⍳12)
(~oneTwoThree≠⍳12) ≡ (oneTwoThree = ⍳12)
Less Than and Greater Than or Equal To are opposite from one another#
This is fairly easy to deduce; in fact, for two numbers ⍵
and ⍺
we can imagine them on the number line. Then only one of three things can happen:
⍵
is to the left of⍺
which can be written as⍵ < ⍺
;⍵
and⍺
lie on the same point, which is⍵ = ⍺
;⍵
is to the right of⍺
which can be written as⍵ > ⍺
;
The Less Than function returns \(1\) for the case 1. above and \(0\) for the cases 2. and 3.; on the other hand the Greater Than or Equal To function returns \(0\) for the case 1. above and \(1\) for the cases 2. and 3. This shows <
and ≥
are opposites from one another.
oneToFive ← 15⍴⍳5
oneToFive
oneTwoThree ← 15⍴⍳3
oneTwoThree
oneToFive < oneTwoThree
(~ oneToFive < oneTwoThree) ≡ ( oneToFive ≥ oneTwoThree)
( oneToFive < oneTwoThree) ≡ (~ oneToFive ≥ oneTwoThree)
Greater Than and Less Than or Equal To are opposite from one another#
The reason why these two functions are opposite from one another is very similar to the explanation for <
and ≥
.
oneToFive ≤ oneTwoThree
(~ oneToFive ≤ oneTwoThree) ≡ ( oneToFive > oneTwoThree)
( oneToFive ≤ oneTwoThree) ≡ (~ oneToFive > oneTwoThree)