Boolean: Difference between revisions
mNo edit summary |
m (Text replacement - "</source>" to "</syntaxhighlight>") |
||
(5 intermediate revisions by 2 users not shown) | |||
Line 7: | Line 7: | ||
The result of a [[comparison]] such as [[Less Than]] is always composed of Booleans. Because Booleans are numbers, arithmetic functions can be used on them directly, for example by [[sum]]ming a result [[vector]] to find out how many times the comparison was true: | The result of a [[comparison]] such as [[Less Than]] is always composed of Booleans. Because Booleans are numbers, arithmetic functions can be used on them directly, for example by [[sum]]ming a result [[vector]] to find out how many times the comparison was true: | ||
< | <syntaxhighlight lang=apl> | ||
3 1 4 1 5 9 2 < 5 | 3 1 4 1 5 9 2 < 5 | ||
1 1 1 1 0 0 1 | 1 1 1 1 0 0 1 | ||
+/ 3 1 4 1 5 9 2 < 5 | +/ 3 1 4 1 5 9 2 < 5 | ||
5 | 5 | ||
</ | </syntaxhighlight> | ||
With [[index origin]] 0, Booleans can also be used as [[Index|indices]] into an array. | With [[index origin]] 0, Booleans can also be used as [[Index|indices]] into an array. | ||
< | <syntaxhighlight lang=apl> | ||
⎕IO←0 | ⎕IO←0 | ||
'-+'[3 1 4 1 5 9 2 < 5] | '-+'[3 1 4 1 5 9 2 < 5] | ||
++++--+ | ++++--+ | ||
</ | </syntaxhighlight> | ||
The use of numbers for Booleans also allows functions to be extended from a Boolean domain to a more general domain. The function [[Compress]] was originally defined to take a Boolean left argument and use it as a filter for the right argument (removing right argument values corresponding to 0), but has generally now been replaced by an extension called [[Replicate]] which can copy right argument values multiple times. | The use of numbers for Booleans also allows functions to be extended from a Boolean domain to a more general domain. The function [[Compress]] was originally defined to take a Boolean left argument and use it as a filter for the right argument (removing right argument values corresponding to 0), but has generally now been replaced by an extension called [[Replicate]] which can copy right argument values multiple times. | ||
< | <syntaxhighlight lang=apl> | ||
1 1 1 1 0 0 1 / '3141592' | 1 1 1 1 0 0 1 / '3141592' | ||
31412 | 31412 | ||
0 4 1 2 0 0 0 / '3141592' | 0 4 1 2 0 0 0 / '3141592' | ||
1111411 | 1111411 | ||
</ | </syntaxhighlight> | ||
== Boolean functions == | == Boolean functions == | ||
Line 35: | Line 35: | ||
{|class=wikitable | {|class=wikitable | ||
! < | ! <syntaxhighlight lang=apl inline>f 0</syntaxhighlight> !! <syntaxhighlight lang=apl inline>f 1</syntaxhighlight> !! Function | ||
|- | |- | ||
| 0 || 0 || Constant 0 | | 0 || 0 || Constant 0 | ||
Line 41: | Line 41: | ||
| 0 || 1 || Identity | | 0 || 1 || Identity | ||
|- | |- | ||
| 1 || 0 || < | | 1 || 0 || <syntaxhighlight lang=apl inline>~</syntaxhighlight> [[Not]] | ||
|- | |- | ||
| 1 || 1 || Constant 1 | | 1 || 1 || Constant 1 | ||
Line 47: | Line 47: | ||
{|class=wikitable | {|class=wikitable | ||
! < | ! <syntaxhighlight lang=apl inline>0 f 0</syntaxhighlight> !! <syntaxhighlight lang=apl inline>0 f 1</syntaxhighlight> !! <syntaxhighlight lang=apl inline>1 f 0</syntaxhighlight> !! <syntaxhighlight lang=apl inline>1 f 1</syntaxhighlight> !! Function | ||
|- | |- | ||
| 0 || 0 || 0 || 0 || Constant 0 | | 0 || 0 || 0 || 0 || Constant 0 | ||
|- | |- | ||
| 0 || 0 || 0 || 1 || < | | 0 || 0 || 0 || 1 || <syntaxhighlight lang=apl inline>∧</syntaxhighlight> [[And]], <syntaxhighlight lang=apl inline>⌊</syntaxhighlight> [[Minimum]] , <syntaxhighlight lang=apl inline>×</syntaxhighlight> [[Times]] | ||
|- | |- | ||
| 0 || 0 || 1 || 0 || < | | 0 || 0 || 1 || 0 || <syntaxhighlight lang=apl inline>></syntaxhighlight> [[Greater Than]] | ||
|- | |- | ||
| 0 || 0 || 1 || 1 || Left argument | | 0 || 0 || 1 || 1 || Left argument | ||
|- | |- | ||
| 0 || 1 || 0 || 0 || < | | 0 || 1 || 0 || 0 || <syntaxhighlight lang=apl inline><</syntaxhighlight> [[Less Than]], <syntaxhighlight lang=apl inline>|</syntaxhighlight> [[Residue]] | ||
|- | |- | ||
| 0 || 1 || 0 || 1 || Right argument | | 0 || 1 || 0 || 1 || Right argument | ||
|- | |- | ||
| 0 || 1 || 1 || 0 || < | | 0 || 1 || 1 || 0 || <syntaxhighlight lang=apl inline>≠</syntaxhighlight> [[Not Equal]] | ||
|- | |- | ||
| 0 || 1 || 1 || 1 || < | | 0 || 1 || 1 || 1 || <syntaxhighlight lang=apl inline>∨</syntaxhighlight> [[Or]], <syntaxhighlight lang=apl inline>⌈</syntaxhighlight> [[Maximum]] | ||
|- | |- | ||
| 1 || 0 || 0 || 0 || < | | 1 || 0 || 0 || 0 || <syntaxhighlight lang=apl inline>⍱</syntaxhighlight> [[Nor]] | ||
|- | |- | ||
| 1 || 0 || 0 || 1 || < | | 1 || 0 || 0 || 1 || <syntaxhighlight lang=apl inline>=</syntaxhighlight> [[Equal]] | ||
|- | |- | ||
| 1 || 0 || 1 || 0 || Right argument negation | | 1 || 0 || 1 || 0 || Right argument negation | ||
|- | |- | ||
| 1 || 0 || 1 || 1 || < | | 1 || 0 || 1 || 1 || <syntaxhighlight lang=apl inline>≥</syntaxhighlight> [[Greater Than or Equal]], <syntaxhighlight lang=apl inline>*</syntaxhighlight> [[Power]] | ||
|- | |- | ||
| 1 || 1 || 0 || 0 || Left argument negation | | 1 || 1 || 0 || 0 || Left argument negation | ||
|- | |- | ||
| 1 || 1 || 0 || 1 || < | | 1 || 1 || 0 || 1 || <syntaxhighlight lang=apl inline>≤</syntaxhighlight> [[Less Than or Equal]], <syntaxhighlight lang=apl inline>!</syntaxhighlight> [[Binomial]] | ||
|- | |- | ||
| 1 || 1 || 1 || 0 || < | | 1 || 1 || 1 || 0 || <syntaxhighlight lang=apl inline>⍲</syntaxhighlight> [[Nand]] | ||
|- | |- | ||
| 1 || 1 || 1 || 1 || Constant 1 | | 1 || 1 || 1 || 1 || Constant 1 | ||
Line 84: | Line 84: | ||
== Boolean optimization == | == Boolean optimization == | ||
Optimizing for Boolean arrays is one special case of using a small [[internal type]] in order to reduce memory usage and improve speed in an APL interpreter. For Booleans this optimization is particularly valuable because each Boolean is representable with a single bit—the smallest discrete quantity available on a CPU. The decision to use packed arrays with eight Booleans for each byte was made by [[Larry Breed]] in [[APL\360]], even though the IBM System/360 did not have the capability to address individual bits. | Optimizing for Boolean arrays is one special case of using a small [[internal type]] in order to reduce memory usage and improve speed in an APL interpreter. For Booleans this optimization is particularly valuable because each Boolean is representable with a single bit—the smallest discrete quantity available on a CPU. The decision to use packed arrays with eight Booleans for each byte was made by [[Larry Breed]] in [[APL\360]], even though the IBM System/360 did not have the capability to address individual bits. Later APLs implemented with bit Booleans include [[APL\3000]], [[SHARP APL]], [[Dyalog APL]], and [[dzaima/APL]]. | ||
Packed Booleans are especially valuable in array languages because only arrays of Booleans are subject to this optimization: a single Boolean in a processor will use an entire register just like an integer or floating-point value. Using a packed representation for arrays of Booleans both decreases memory usage by a factor of eight and makes faster algorithms possible, as eight times more one-bit values may be fit in a single CPU register (and thus manipulated at once) than one-byte values. However, packed Boolean arrays have a drawback: while optimized algorithms on bit Booleans are usually faster than those on byte Booleans, packed Boolean algorithms are often considerably harder to implement, and unoptimized algorithms using bit Booleans tend to be slower. This is because bits in memory cannot be addressed directly on a modern computing architecture. To read or write a single bit at an arbitrary offset, the byte containing it must be read and then the appropriate bit picked out. | Packed Booleans are especially valuable in array languages because only arrays of Booleans are subject to this optimization: a single Boolean in a processor will use an entire register just like an integer or floating-point value. Using a packed representation for arrays of Booleans both decreases memory usage by a factor of eight and makes faster algorithms possible, as eight times more one-bit values may be fit in a single CPU register (and thus manipulated at once) than one-byte values. However, packed Boolean arrays have a drawback: while optimized algorithms on bit Booleans are usually faster than those on byte Booleans, packed Boolean algorithms are often considerably harder to implement, and unoptimized algorithms using bit Booleans tend to be slower. This is because bits in memory cannot be addressed directly on a modern computing architecture. To read or write a single bit at an arbitrary offset, the byte containing it must be read and then the appropriate bit picked out. | ||
Line 94: | Line 94: | ||
* Dyalog Blog: [[Marshall Lochbaum]], [https://www.dyalog.com/blog/2018/06/expanding-bits-in-shrinking-time/ "Expanding Bits in Shrinking Time"] | * Dyalog Blog: [[Marshall Lochbaum]], [https://www.dyalog.com/blog/2018/06/expanding-bits-in-shrinking-time/ "Expanding Bits in Shrinking Time"] | ||
Because they are so small relative to CPU registers, Booleans can make [[wikipedia:SIMD|SIMD]] (Single Instruction Multiple Data) techniques viable even in processors with no dedicated SIMD unit. Programming in this way is called [[wikipedia:SWAR|SWAR]] (SIMD Within a Register), and is considerably easier when working with bit Booleans than when working with integers. | Because they are so small relative to CPU registers, Booleans can make [[wikipedia:SIMD|SIMD]] (Single Instruction Multiple Data) techniques viable even in processors with no dedicated SIMD unit. Programming in this way is called [[wikipedia:SWAR|SWAR]] (SIMD Within a Register), and is considerably easier when working with bit Booleans than when working with integers. While most processors now have SIMD registers and instructions, current SIMD implementations don't provide all the bitwise operations that are available for ordinary registers, such as addition or bitwise shifts on entire registers. Boolean SWAR programming can be useful to more easily develop algorithms which are fast (often beating dedicated SIMD optimizations with each Boolean stored in a byte) while remaining architecture independent. | ||
== External links == | == External links == | ||
* [[Bob Smith]], [http://www.sudleyplace.com/APL/boolean.pdf "Boolean Functions"] | * [[Bob Smith]], [http://www.sudleyplace.com/APL/boolean.pdf "Boolean Functions"] | ||
* Jonathan Barman, [http://archive.vector.org.uk/trad/v011/barman011_127.pdf APL and Partitioned Data] (a follow-up on Smith's paper) | |||
* [[Eugene McDonnell]], [https://www.jsoftware.com/papers/eem/caret.htm "The Caret and the Stick Functions"] (on classifying Boolean functions). | * [[Eugene McDonnell]], [https://www.jsoftware.com/papers/eem/caret.htm "The Caret and the Stick Functions"] (on classifying Boolean functions). | ||
* [[Phil Last]], [http://archive.vector.org.uk/art10501140 "Boolean Reductions"] | * [[Phil Last]], [http://archive.vector.org.uk/art10501140 "Boolean Reductions"] | ||
* [[John Scholes]], [https://www.dyalog.com/blog/2014/10/data-driven-conditionals-2/ "Data-driven Conditionals"] | * [[John Scholes]], [https://www.dyalog.com/blog/2014/10/data-driven-conditionals-2/ "Data-driven Conditionals"] | ||
{{APL features}}[[Category:Numbers]] |
Latest revision as of 22:10, 10 September 2022
0 1
|
In array languages, Boolean data consists only of the numbers 0 and 1 (outside of APL, Boolean data may use any two values). Boolean values are used in APL whenever a "true" or "false" value is required, that is, the truth value of a logical proposition such as a comparison of two scalars. The identification of "true" with 1 and "false" with 0 is a simplification of the Iverson bracket, a notation which allowed a truth value to be converted into a number. A notable feature of APL implementations in relation to other language families is their tendency to use bit Booleans (eight in each byte) rather than byte Booleans, a feature which is difficult to implement but increases storage density and can also greatly speed up computation on Boolean arrays.
Examples
The result of a comparison such as Less Than is always composed of Booleans. Because Booleans are numbers, arithmetic functions can be used on them directly, for example by summing a result vector to find out how many times the comparison was true:
3 1 4 1 5 9 2 < 5 1 1 1 1 0 0 1 +/ 3 1 4 1 5 9 2 < 5 5
With index origin 0, Booleans can also be used as indices into an array.
⎕IO←0 '-+'[3 1 4 1 5 9 2 < 5] ++++--+
The use of numbers for Booleans also allows functions to be extended from a Boolean domain to a more general domain. The function Compress was originally defined to take a Boolean left argument and use it as a filter for the right argument (removing right argument values corresponding to 0), but has generally now been replaced by an extension called Replicate which can copy right argument values multiple times.
1 1 1 1 0 0 1 / '3141592' 31412 0 4 1 2 0 0 0 / '3141592' 1111411
Boolean functions
A monadic or dyadic function (sometimes scalar function) which has a Boolean result when passed Boolean arguments is called a Boolean function. Two Boolean functions are considered the same if they have the same result for every Boolean input. Since there are a finite number of possible inputs (two for monadic functions and four for dyadic functions), and only two results, there are only a finite number of Boolean functions: four monadic and sixteen dyadic.
Every Boolean function which depends on all of its arguments and is not the monadic identity function is represented by a scalar function in APL.
f 0 |
f 1 |
Function |
---|---|---|
0 | 0 | Constant 0 |
0 | 1 | Identity |
1 | 0 | ~ Not
|
1 | 1 | Constant 1 |
0 f 0 |
0 f 1 |
1 f 0 |
1 f 1 |
Function |
---|---|---|---|---|
0 | 0 | 0 | 0 | Constant 0 |
0 | 0 | 0 | 1 | ∧ And, ⌊ Minimum , × Times
|
0 | 0 | 1 | 0 | > Greater Than
|
0 | 0 | 1 | 1 | Left argument |
0 | 1 | 0 | 0 | < Less Than, | Residue
|
0 | 1 | 0 | 1 | Right argument |
0 | 1 | 1 | 0 | ≠ Not Equal
|
0 | 1 | 1 | 1 | ∨ Or, ⌈ Maximum
|
1 | 0 | 0 | 0 | ⍱ Nor
|
1 | 0 | 0 | 1 | = Equal
|
1 | 0 | 1 | 0 | Right argument negation |
1 | 0 | 1 | 1 | ≥ Greater Than or Equal, * Power
|
1 | 1 | 0 | 0 | Left argument negation |
1 | 1 | 0 | 1 | ≤ Less Than or Equal, ! Binomial
|
1 | 1 | 1 | 0 | ⍲ Nand
|
1 | 1 | 1 | 1 | Constant 1 |
Boolean optimization
Optimizing for Boolean arrays is one special case of using a small internal type in order to reduce memory usage and improve speed in an APL interpreter. For Booleans this optimization is particularly valuable because each Boolean is representable with a single bit—the smallest discrete quantity available on a CPU. The decision to use packed arrays with eight Booleans for each byte was made by Larry Breed in APL\360, even though the IBM System/360 did not have the capability to address individual bits. Later APLs implemented with bit Booleans include APL\3000, SHARP APL, Dyalog APL, and dzaima/APL.
Packed Booleans are especially valuable in array languages because only arrays of Booleans are subject to this optimization: a single Boolean in a processor will use an entire register just like an integer or floating-point value. Using a packed representation for arrays of Booleans both decreases memory usage by a factor of eight and makes faster algorithms possible, as eight times more one-bit values may be fit in a single CPU register (and thus manipulated at once) than one-byte values. However, packed Boolean arrays have a drawback: while optimized algorithms on bit Booleans are usually faster than those on byte Booleans, packed Boolean algorithms are often considerably harder to implement, and unoptimized algorithms using bit Booleans tend to be slower. This is because bits in memory cannot be addressed directly on a modern computing architecture. To read or write a single bit at an arbitrary offset, the byte containing it must be read and then the appropriate bit picked out.
Boolean algorithms are a frequent topic of discussion for APL implementors at the Dyalog user meeting. The following talks all focus primarily on Boolean algorithms:
- Dyalog '08 (05): Roger Hui, "Performance Improvements in Dyalog: A Case Study"
- Dyalog '16 U08: Bob Bernecky, "A Compendium of SIMD Boolean Array Algorithms in APL"
- Dyalog '17 D08: Marshall Lochbaum, "Moving Bits Faster in Dyalog 16.0"
- Dyalog Blog: Marshall Lochbaum, "Expanding Bits in Shrinking Time"
Because they are so small relative to CPU registers, Booleans can make SIMD (Single Instruction Multiple Data) techniques viable even in processors with no dedicated SIMD unit. Programming in this way is called SWAR (SIMD Within a Register), and is considerably easier when working with bit Booleans than when working with integers. While most processors now have SIMD registers and instructions, current SIMD implementations don't provide all the bitwise operations that are available for ordinary registers, such as addition or bitwise shifts on entire registers. Boolean SWAR programming can be useful to more easily develop algorithms which are fast (often beating dedicated SIMD optimizations with each Boolean stored in a byte) while remaining architecture independent.
External links
- Bob Smith, "Boolean Functions"
- Jonathan Barman, APL and Partitioned Data (a follow-up on Smith's paper)
- Eugene McDonnell, "The Caret and the Stick Functions" (on classifying Boolean functions).
- Phil Last, "Boolean Reductions"
- John Scholes, "Data-driven Conditionals"
APL features [edit] | |
---|---|
Built-ins | Primitives (functions, operators) ∙ Quad name |
Array model | Shape ∙ Rank ∙ Depth ∙ Bound ∙ Index (Indexing) ∙ Axis ∙ Ravel ∙ Ravel order ∙ Element ∙ Scalar ∙ Vector ∙ Matrix ∙ Simple scalar ∙ Simple array ∙ Nested array ∙ Cell ∙ Major cell ∙ Subarray ∙ Empty array ∙ Prototype |
Data types | Number (Boolean, Complex number) ∙ Character (String) ∙ Box ∙ Namespace ∙ Function array |
Concepts and paradigms | Conformability (Scalar extension, Leading axis agreement) ∙ Scalar function (Pervasion) ∙ Identity element ∙ Complex floor ∙ Array ordering (Total) ∙ Tacit programming (Function composition, Close composition) ∙ Glyph ∙ Leading axis theory ∙ Major cell search ∙ First-class function |
Errors | LIMIT ERROR ∙ RANK ERROR ∙ SYNTAX ERROR ∙ DOMAIN ERROR ∙ LENGTH ERROR ∙ INDEX ERROR ∙ VALUE ERROR ∙ EVOLUTION ERROR |