From b83cc8e754952a276a4416ca0971d5e5ef3816b9 Mon Sep 17 00:00:00 2001 From: Bart Jablonski Date: Mon, 4 Sep 2023 16:33:53 +0200 Subject: [PATCH] The DFA package [ver. 0.5.6] The DFA package [ver. 0.5.6] Package regenerated with the latest version of the SAS Packages Framework (20230904). SHA256 digest for the latest version of `DFA`: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62 --- README.md | 2 +- dfa.md | 8 +- dfa.zip | Bin 48275 -> 48503 bytes hist/0.5.6/dfa.md | 1597 ++++++++++++++++++++++++++++++++++++++++++++ hist/0.5.6/dfa.zip | Bin 0 -> 48503 bytes 5 files changed, 1602 insertions(+), 5 deletions(-) create mode 100644 hist/0.5.6/dfa.md create mode 100644 hist/0.5.6/dfa.zip diff --git a/README.md b/README.md index 2857282..253133f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a pr Run `%helpPackage(DFA,createDFArray)` to find examples. -SHA256 digest for the latest version of `DFA`: F*924711C77E413B8CFC18336DDA2293A9F5294D02E267C1BB7BC876B4AF0AABE4 +SHA256 digest for the latest version of `DFA`: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62 [**Documentation for DFA**](./dfa.md "Documentation for DFA") diff --git a/dfa.md b/dfa.md index 2488e00..0ab0381 100644 --- a/dfa.md +++ b/dfa.md @@ -18,7 +18,7 @@ --- -# The DFA package [ver. 0.5.5] ############################################### +# The DFA package [ver. 0.5.6] ############################################### The **DFA** (a.k.a. *Dynamic Function Array*) package implements: - dynamic numeric and character arrays, @@ -52,10 +52,10 @@ Package contains: 12. exec generatearrays 13. clean generatearrays -*SAS package generated by generatePackage, version 20230411* +*SAS package generated by generatePackage, version 20230905* -The SHA256 hash digest for package BasePlus: -`F*924711C77E413B8CFC18336DDA2293A9F5294D02E267C1BB7BC876B4AF0AABE4` +The SHA256 hash digest for package DFA: +`F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62` --- # Content description ############################################################################################ diff --git a/dfa.zip b/dfa.zip index d5b2c5c403e4f389a0db8f22a2a0de360237caad..c189a62bfead338dde1676f6ceb42e13e7f086bf 100644 GIT binary patch delta 10862 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 delta 10546 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 ############################################### + +The **DFA** (a.k.a. *Dynamic Function Array*) package implements: + - dynamic numeric and character arrays, + - dynamic stacks (filo), + - dynamic queues (fifo), + - dynamic ordered stacks, + - priority queues, + - bitmap. + +The package provides a set of *macros*, +which allows to *generate* `call routines` +simulating data structures mentioned above. + +Few exemplary functions are also generated. +See particular macro help for further details. + +--- + +Package contains: +1. macro createdfarray +2. macro createdharray +3. macro createdhfifo +4. macro createdhordstack +5. macro createdhprtqueue +6. macro createdhstack +7. proto bit64andprotodfa +8. proto bit64orprotodfa +9. functions bit64anddfa +10. functions bit64ordfa +11. macro createdfbitmap +12. exec generatearrays +13. clean generatearrays + +*SAS package generated by generatePackage, version 20230905* + +The SHA256 hash digest for package DFA: +`F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62` + +--- +# Content description ############################################################################################ + +## >>> `%createDFArray()` macro: <<< ####################### + +The `%createDFArray()` macro allows to generate +a `dynamic function array` which is a FCMP based +approach to create *dynamically* allocated **numeric** +array with possible values searching and `WHICHN()` +function emulation. + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDFArray( + arrayName + <,debug=0> + <,simple=0> + <,resizeFactor=0> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayName` - *Required*, creates a FCMP call subroutine which is also + an array name. In the data step it is used in form of + a call subroutine, e.g. `call arrayName("Allocate", -3, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `simple=` - *Optional*, the default value is `0`. A *simple* dynamic + function array is one which is not searchable and does not + allows to use `which()` functionality. + If set to `1` then it disables `SEARCH` and `WHICH` functionality. + See examples below for details. + +* `resizeFactor=` - *Optional*, the default value is `0`. If set to `0` then + the dynamic array size is not changeable(mutable) after initial + size allocation. + If set not to `0` then arrays dimensions are mutable after allocation, + i.e. even if an array is allocated for ten elements (like `A[1:10]`) + you can do `A[17] = 42` and it will resize itself dynamically. + *Hint!* Set to, e.g. 4999, for faster allocation process. + See examples below for details. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &arrayName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `R`, `Return` - to get the data from an array, + - `I`, `Input` - to insert the data into an array, + - `+`, `Add` - to increment given position by a value, + - `C`, `Clear` - to reduce an array to a single empty cell, + - `A`, `Allocate` - to reserve space for array width and set starting values, + - `D`, `Dimension` - to return minimal and maximal index of an array, + - `F`, `Find`, `Exist` - to find out if a given value exist in an array, + - `W`, `Which` - to search the first position of data in array, `WHICHN()` function emulator, + - `Sum` - to return the sum of non-missing elements of an array, + - `Nonmiss` - to return the number of non-missing elements of an array, + - `Avg`, `Mean`, `Average` - to return the average of non-missing elements of an array, + - `Min`, `Minimum` - to return the minimum of non-missing elements of an array, + - `Max`, `Maximum` - to return the maximum of non-missing elements of an array. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return`/ `I`, `Input`/ `+`, `Add` it takes + an arrays index from (into) which data is get (put), + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` sets the value of the minposition, i.e. the minimal position of the array index, + - for `D`, `Dimension` it returns value of the minposition, + - for `Sum`, `Nonmiss`, `Avg`, `Mean`, `Average`, `Min`, `Minimum`, `Max`, and `Maximum` is ignored, + - for `F`, `Find`, `Exist` it returns number of occurrences of a given value in an array, + - for `W`, `Which` it returns position the first occurrence of a given value in an array. + +.3 `value` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return` it holds value retrieved from an array on a given position, + - for `I`, `Input` it holds the value inserted into an array on a given position, + - for `+`, `Add` it holds the value that is used to increment an array value at a given position, + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` it sets the value of the maxposition, i.e. maximal position of the array index, + - for `D`, `Dimension` it returns value of the maxposition + - for `Sum`, `Nonmiss`, `Avg`, `Mean`, `Average`, `Min`, `Minimum`, `Max`, and `Maximum` it returns + the calculated summary value, + - for `F`, `Find`, `Exist`, `W`, `Which` is the value to be searched in an array. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Searchable, and Immutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSI); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + call ArrDSI("Allocate", 1, 10); + L = 0; H = 0; + call ArrDSI("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H; + call ArrDSI("Input", i, i**2); + end; + + * searchability allows to find number of occurrences of value in the array ; + F = .; + call ArrDSI("Find", F, 16); + put "Value 16 occurs " F "times"; + call ArrDSI("Find", F, 17); + put "Value 17 occurs " F "times"; + + * increase value of cell 4 by 1, and verify at WHICH position is 17 (by searchability); + call ArrDSI("+", 4, 1); + call ArrDSI("Which", F, 17); + put "Value 17 occurred for the first time at position " F; + + * get values from the array ; + Value = .; + do i = L to H; + call ArrDSI("Output", i, Value); + put i= Value=; + end; + + * some basic statistics ; + call ArrDSI("Sum", ., STAT); put "sum = " STAT; + call ArrDSI("Avg", ., STAT); put "avg = " STAT; + call ArrDSI("Min", ., STAT); put "min = " STAT; + call ArrDSI("Max", ., STAT); put "max = " STAT; + call ArrDSI("Cnt", ., STAT); put "cnt = " STAT; + + * immutability does _not_ allow to increase dimensions automatically; + * this line returns an error ; + call ArrDSI("Input", 42, -1); + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Searchable, and Mutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSM, resizefactor=17); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + call ArrDSM("Allocate", -2, 2); + + do i = -2 to 2; + call ArrDSM("Input", i, 2**i); + end; + + L = .; H = .; + call ArrDSM("Dim", L, H); + put L= H=; + + * mutability allows to increase dimensions automatically + * create index 3 and -3; + call ArrDSM("+", 3, 8); + call ArrDSM("+",-3, 0.125); + call ArrDSM("Dim", L, H); + put L= H=; + + Value = .; + do i = L to H; + call ArrDSM("O", i, Value); + put i= Value=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Dynamic, non-searchable (a.k.a. SiMPle), and Immutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSMPLI, simple=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example3; + call ArrDSMPLI("Allocate", -2, 2); + + do i = -2 to 2; + call ArrDSMPLI("Input", i, 2**i); + end; + + * non-searchable array (a.k.a. simple) does not allow ; + * to find number of occurrences of value in the array ; + * and verify what is the first position of a value ; + * this lines return a warning ; + call ArrDSMPLI("Exist", i, 1); + call ArrDSMPLI("Which", i, 1); + run; + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Dynamic, non-searchable (a.k.a. SiMPle), and Mutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSMPLM, simple=1, resizefactor=42); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example4; + call ArrDSMPLM("Allocate", 1, 1); + + * mutability allows to increase dimensions automatically ; + do i = -12 to 12; + call ArrDSMPLM("Input", i, i*2); + end; + + * non-searchable array (a.k.a. simple) does not allow ; + * to find number of occurrences of value in the array ; + * and verify what is the first position of a value ; + * this lines return a warning ; + i = .; + call ArrDSMPLM("Exist", i, -24); + put "Exist " i=; + call ArrDSMPLM("Which", i, 24); + put "Which " i=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- +## >>> `%createDHArray()` macro: <<< ####################### + +The `%createDHArray()` macro allows to generate +a `dynamic hash array` which is a FCMP based approach +to create *dynamically* allocated **numeric** +or **character** array + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHArray( + arrayName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayName` - *Required*, creates a FCMP call subroutine which is also + an array name. In the data step it is used in form of + a call subroutine, e.g. `call arrayName("Allocate", -3, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &arrayName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `R`, `Return` - to get the data from an array, + - `I`, `Input` - to insert the data into an array, + - `C`, `Clear` - to reduce an array to a single empty cell, + - `L`, `Low`, `Lower`, `Lbound` - to return minimal position of index, + - `H`, `High`, `Higher`, `Hbound` - to return maximal position of index. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return`/ `I`, and `Input` it is an array + index from (into) which data is get (put), + - for `C` it is ignored, + - for `L`, `Low`, `Lower`, and `Lbound` it returns the first position of an index, + - for `H`, `High`, `Higher`, and `Hbound` it returns the last position of an index, + - otherwise is not modified. + +3. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `R`, and `Return` it holds value retrieved from an array from a given position, + - for `I`, `Input` it holds the value inserted into an array into a given position, + - for `C` is ignored, + - for `L`, `Low`, `Lower`, and `Lbound` returns first value of index, + - for `H`, `High`, `Higher`, and `Hbound` returns last value of index, + - otherwise is not modified. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHArray(ArrDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); + do _I_ = -1e&zeros. to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call ArrDHC("Input", _I_, _X_); + end; + t = time() - t; + put t= / _X_= /; + + * get the size info ; + LB = 0; HB = 0; + drop LB HB; + call ArrDHC('Lbound', LB, _X_); + call ArrDHC('Hbound', HB, _X_); + put LB= HB= /; + + t = time(); + do _I_ = HB + 1 to LB - 1 by -1; + call ArrDHC('Output', _I_, _X_); + output; + end; + t = time() - t; + put t= / _X_= /; + + * clear for further reuse ; + call ArrDHC('C', ., ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHArray(ArrDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do i = -2 to 2; + call ArrDHN("Input", i, 2**i); + end; + + do i = -2 to 2; + call ArrDHN("+", i, -10); + end; + + v = .; + do i = -2 to 2; + call ArrDHN("Output", i, v); + put i= v=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- +## >>> `%createDHFifo()` macro: <<< ####################### + +The `%createDHFifo()` macro allows to generate +a `dynamic hash fifo` which is a FCMP based approach +to create dynamically allocated numeric or character +"first in first out" [queue](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) + +Interesting reading about implementing a fifo via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHFifo( + fifoName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `fifoName` - *Required*, creates a FCMP call subroutine which is also + a fifo name. In the data step it is used in form of + a call subroutine, e.g. `call fifoName("Enqueue", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &fifoName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `D`, `Dequeue`, `R`, `Return` - to get the data from a fifo (and remove it from the fifo) + - `I`, `Input`, `E`, `Enqueue`, and `Insert` - to insert the data into a fifo + - `C`, `Clear` - to reduce a fifo to an empty one + - `P`, `Peek`, `T`, and `Tail` - to peek the data from a fifo (and NOT remove it from the fifo) + - `H`, `Head` - to peek the data from a fifo head (and NOT remove it from the fifo) + - `Sum` - returns sum of nonmissing numeric elements of a stack + - `Avg`, `Mean`, `Average` - returns average of nonmissing numeric elements of a stack + - `Nonmiss`, `Cnt` - returns number of nonmissing elements of a stack + - `Height` - returns height a stack + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` it holds the value popped from the fifo, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds the value to be pushed into the fifo, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` holds the value peeked from the fifo, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, and `Height` it returns calculated summary value. + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character fifo: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHFifo(FifoDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); drop t; + do _I_ = 1 to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call FifoDHC("Enqueue", _X_); + end; + t = time() - t; + + call FifoDHC("Height", _X_); + put t= / _X_=; + + t = time(); + do _I_ = 1 to 1e&zeros. + 3; + call FifoDHC('Dequeue', _X_); + output; + end; + t = time() - t; + + call FifoDHC("Height", _X_); + put t= / _X_=; + + %* clear for further reuse *; + call FifoDHC('Clear', ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric fifo: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHFifo(FifoDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _I_ = 1,.,2,.,3,.,4,.,5,.,6; + call FifoDHN("E", _I_); + end; + + call FifoDHN("Sum", _I_); + put "Sum " _I_=; + + call FifoDHN("Avg", _I_); + put "Avg " _I_=; + + call FifoDHN("Cnt", _I_); + put "Cnt " _I_=; + + call FifoDHN("Height", _I_); + put "Height " _I_=; + + call FifoDHN("Tail", _I_); + put "Tail of fifo is " _I_=; + + call FifoDHN("Height", _I_); + put "Height after Tail " _I_=; + + call FifoDHN("Head", _I_); + put "Head of fifo is " _I_=; + + call FifoDHN("Height", _I_); + put "Height after Head" _I_=; + + _X_ = 0; + do _I_ = 1 to _I_; + call FifoDHN('D', _X_); + output; + end; + + call FifoDHN("Height", _I_); + put "Height " _I_=; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- +## >>> `%createDHOrdStack()` macro: <<< ####################### + +The `%createDHOrdStack()` macro allows to generate +a `dynamic ORDERED hash stack` which is a FCMP based approach +to create dynamically allocated numeric or character +*ordered* [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) + +Interesting reading about implementing a stack via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHOrdStack( + fifoName + <,debug=0> + <,type=8> + <,order=A> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `stackName` - *Required*, creates a FCMP call subroutine which is also + a stack name. In the data step it is used in form of + a call subroutine, e.g. `call stackName("Push", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `order=` - *Optional*, the default value is `A`. + Indicates a method of ordering of the stack, + allowed values are: `A` for ascending and `D` for descending. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &stackName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` - to get the data from a stack (and remove it from the top), + - `I`, `Input`, `Push`, `Put`, `Insert` - to insert the data into a stack, + - `C`, `Clear` - to reduce a stack to an empty one, + - `P`, `Peek` - to peek the data from a stack (and NOT remove it from the top), + - `Sum` - returns sum of non-missing numeric elements of a stack, + - `Avg`, `Mean`, `Average` - returns average of non-missing numeric elements of a stack, + - `Nonmiss`, `Cnt`, `Nnm` - returns number of non-missing elements of a stack, + - `Height` - returns height a stack, + - `Min`, `Minimum` - returns minimum of non-missing elements of a stack, + - `Max`, `Maximum` - returns maximum of non-missing elements of a stack. + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` it holds a value popped from a stack, + - for `I`, `Input`, `Push`, `Put`, `Insert` it holds a value to be pushed into a stack, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` it holds a value peeked from a stack, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height`, `Min`, `Minimum`, `Max`, and `Maximum` + it returns calculated summary value, + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character Descending Ordered stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHOrdStack(DescStackC, type = $ 12, order=D); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + + do _X_ = "A","B"," ","C","A"," ","B","C"; + call DescStackC("Push", _X_); + end; + + length S $ 12; + call DescStackC('Height', S); + put 'Height ' S; + + do until(strip(S) = "0"); + call DescStackC('Get', _X_); + call DescStackC('Height', S); + put S= _X_=; + output; + end; + + %* clear for further reuse *; + call DescStackC('Clear',''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric Ascending Ordered stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHOrdStack(DescStackN, order=A); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + call missing(Sum, Avg, Min, Max, Cnt, Hgt, Peek); + do _X_ = 1,6,2,.,5,3,4; + call DescStackN("Put", _X_); + call DescStackN('Sum', Sum); + call DescStackN('Avg', Avg); + call DescStackN('Min', Min); + call DescStackN('Max', Max); + call DescStackN('Cnt', Cnt); + call DescStackN('Height', Hgt); + put (_ALL_) (=); + end; + + call DescStackN('Peek', Peek); + put Peek=; + + do _I_ = 1 to Hgt; + call DescStackN('Output', _X_); + keep _X_; + if _X_ > .z then output; + end; + + call DescStackN('Peek', Peek); + put Peek=; + + %* clear for further reuse *; + call DescStackN('Clear',.); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- +## >>> `%createDHPrtQueue()` macro: <<< ####################### + + +The `%createDHPrtQueue()` macro allows to generate +a `dynamic PRIORITY hash queue` which is a FCMP based approach +to create dynamically allocated numeric or character +[priority queue](https://en.wikipedia.org/wiki/Priority_queue) + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHPrtQueue( + fifoName + <,debug=0> + <,type=8> + <,newOnTop=+> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `queueName` - *Required*, creates a FCMP call subroutine which is also + a queue name. In the data step it is used in form of + a call subroutine, e.g. `call queueName("Bottom", 1, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `newOnTop=` - *Optional*, the default value is `+`. + Indicates how to keep order in the same priority group, + allowed values are `+` or `-`. Plus(`+`) sets new elements + at the top of the group, minus(`-`) at the bottom. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &queueName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `D`, `Dequeue`, `R`, `Return` - it pops/gets/outputs the data from the queue head (high priority), + - `B`, `Bottom` - it pops/gets/outputs the data from the queue tail (low priority), + - `I`, `Input`, `E`, `Enqueue`, `Insert` - it push/puts/inserts the data into the queue, + - `C`, `Clear` - it reduces a queue to an empty one, + - `H`, `Head` - it peeks the data from the queue head and NOT removes it, + - `T`, `Tail` - it peeks the data from the queue tail and NOT removes it, + - `Sum` - it returns sum of non-missing *numeric* elements of the queue, + - `Avg`, `Mean`, `Average` - it returns average of non-missing *numeric* elements of the queue, + - `Nonmiss`, `Cnt` - it returns number of non-missing elements of the queue, + - `Height` - it returns height of the queue. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` and `B`, `Bottom`, or `H`, `Head`, `T`, `Tail` + it holds a priority level of value popped from the queue, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds a priority level of value to be pushed into the queue, + - for `C` ignored, + - for *numeric* queue and `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` returns calculated summary value. + +3. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` and `B`, `Bottom` or `H`, `Head`, `T`, `Tail` + it holds a value popped from the queue, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds a value to be pushed into the queue, + - for `C` ignored, + - for *numeric* queue and `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` returns calculated summary value, + - otherwise does not modify value. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character Priority queue: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHPrtQueue(PriorityQueuePC, type = $ 12, newOnTop=+); + %createDHPrtQueue(PriorityQueueNC, type = $ 12, newOnTop=-); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + + _I_ = .; + length _X_ _Y_ $ 3; + do _X_ = "AAA","BBB","CCC","AA","BB","CC","A","B","C"; + _I_ + 1; + call PriorityQueuePC("I", mod(_I_, 3), _X_); + call PriorityQueueNC("I", mod(_I_, 3), _X_); + end; + + Height = .; + call PriorityQueuePC('Height', Height, ''); + put Height=; + + do until(Height = 0); + call PriorityQueuePC('Dequeue', _I_, _X_); + call PriorityQueueNC("Dequeue", _I_, _Y_); + call PriorityQueueNC('Height', Height, ''); + put (_ALL_) (=); + output; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric Priority queue: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHPrtQueue(PriorityQueueN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _X_ = -5 to 5; + call PriorityQueueN("Enqueue", abs(_X_), _X_); + end; + + call missing(Sum, Avg, Cnt, Hgt); + call PriorityQueueN('Sum', ., Sum); + call PriorityQueueN('Avg', ., Avg); + call PriorityQueueN('Cnt', ., Cnt); + call PriorityQueueN('Height', ., Hgt); + put (_ALL_) (=); + + do _N_ = 1 to Hgt; + call PriorityQueueN("Dequeue", _X_, _Y_); + put _X_= _Y_=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- +## >>> `%createDHStack()` macro: <<< ####################### + +The `%createDHStack()` macro allows to generate +a `dynamic hash stack` which is a FCMP based approach +to create dynamically allocated numeric or character +[stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) + +Interesting reading about implementing a stack via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHStack( + fifoName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `stackName` - *Required*, creates a FCMP call subroutine which is also + a stack name. In the data step it is used in form of + a call subroutine, e.g. `call stackName("Push", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &stackName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` - to get the data from a stack (and remove it from the top), + - `I`, `Input`, `Push`, `Put`, `Insert` - to insert the data into a stack, + - `C`, `Clear` - to reduce a stack to an empty one, + - `P`, `Peek` - to peek the data from a stack (and NOT remove it from the top), + - `Sum` - returns sum of non-missing numeric elements of a stack, + - `Avg`, `Mean`, `Average` - returns average of non-missing numeric elements of a stack, + - `Nonmiss`, `Cnt`, `Nnm` - returns number of non-missing elements of a stack, + - `Height` - returns height a stack, + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` it holds a value popped from a stack, + - for `I`, `Input`, `Push`, `Put`, `Insert` it holds a value to be pushed into a stack, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` it holds a value peeked from a stack, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` it returns calculated summary value, + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHStack(StackDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); drop t; + do _I_ = 1 to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call StackDHC("Put", _X_); + end; + t = time() - t; + + call StackDHC("Height", _X_); + put t= / _X_=; + + t = time(); + do _I_ = 1 to 1e&zeros. + 3; + call StackDHC('Pop', _X_); + output; + end; + t = time() - t; + + call StackDHC("Height", _X_); + put t= / _X_=; + + %* clear for further reuse *; + call StackDHC('Clear', ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHStack(StackDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _I_ = 1,.,2,.,3,.,4,.,5,.,6; + call StackDHN("Put", _I_); + end; + + call StackDHN("Sum", _I_); + put "Sum " _I_=; + + call StackDHN("Avg", _I_); + put "Avg " _I_=; + + call StackDHN("Cnt", _I_); + put "Cnt " _I_=; + + call StackDHN("Height", _I_); + put "Height " _I_=; + + _X_ = 0; + do _I_ = 1 to _I_; + call StackDHN('Pop', _X_); + output; + end; + + call StackDHN("Height", _I_); + put "Height " _I_=; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `bit64orPROTOdfa()` proto function: <<< ####################### + +The **bit64orPROTOdfa()** is external *C* function, +this is the implementation of the *bitwise OR* operation +on doubles. A double is returned. + +**Caution!** For SAS numeric values *only* operations on first 53 bits are valid! + +The function is used **internally** by functions in the *DFA* package. + +### SYNTAX: ################################################################### + +The basic syntax is the following: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64orPROTOdfa(i, j) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `i` - A double numeric argument. + +2. `j` - A double numeric argument. + +--- + +## >>> `bit64andPROTOdfa()` proto function: <<< ####################### + +The **bit64andPROTOdfa()** is external *C* function, +this is the implementation of the *bitwise AND* operation +on doubles. A double is returned. + +**Caution!** For SAS numeric values *only* operations on first 53 bits are valid! + +The function is used **internally** by functions in the *DFA* package. + +### SYNTAX: ################################################################### + +The basic syntax is the following: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64andPROTOdfa(i, j) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `i` - A double numeric argument. + +2. `j` - A double numeric argument. + +--- + +## >>> `bit64orDFA()` subroutine: <<< ####################### + +The **bit64orDFA()** function is an alternative to +the 32 bit bitwise `BOR()` function working on SAS numerics. +Allows to work on *up to* 53 bits of SAS numeric value. + +The `bit64orDFA()` is an *internal* function of the `DFA` package. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64orDFA(a, b) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `a` - Argument is a SAS numeric values. + +2. `B` - Argument is a SAS numeric values. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Basic test of `bit64orDFA()` and `bit64andDFA()` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options ls = max ps = max; + %let M = 53 ; %* 53 is maximum valid value; + data _null_; + array bitmask [ 0: &M] _temporary_ ; + do P = 1 to &M ; + bitmask[P] = 2**(P-1) ; + put bitmask[P] = binary54. @; + put bitmask[P] = best32.; + end ; + bitmask[0] = bitmask[&M.] ; + put bitmask[0] = best32. /; + + a=0; + put a = binary54.; + do P = 1 to &M ; + a = BIT64ORDFA (a, bitmask[P]) ; + put a = binary54.; + end; + put; + + b = 0; + put b = binary54./; + do P = 1 to &M ; + b + (BIT64ANDDFA (a, bitmask[P]) ne .) ; + put b = best32.; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `bit64andDFA()` subroutine: <<< ####################### + +The **bit64andDFA()** function is an alternative to +the 32 bit bitwise `BAND()` function working on SAS numerics. +Allows to work on *up to* 53 bits of SAS numeric value. + +The `bit64andDFA()` is an *internal* function of the `DFA` package. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64andDFA(a, b) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `a` - Argument is a SAS numeric values. + +2. `B` - Argument is a SAS numeric values. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Basic test of `bit64orDFA()` and `bit64andDFA()` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options ls = max ps = max; + %let M = 53 ; %* 53 is maximum valid value; + data _null_; + array bitmask [ 0: &M] _temporary_ ; + do P = 1 to &M ; + bitmask[P] = 2**(P-1) ; + put bitmask[P] = binary54. @; + put bitmask[P] = best32.; + end ; + bitmask[0] = bitmask[&M.] ; + put bitmask[0] = best32. /; + + a=0; + put a = binary54.; + do P = 1 to &M ; + a = BIT64ORDFA (a, bitmask[P]) ; + put a = binary54.; + end; + put; + + b = 0; + put b = binary54./; + do P = 1 to &M ; + b + (BIT64ANDDFA (a, bitmask[P]) ne .) ; + put b = best32.; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `%createDFBitmap()` macro: <<< ####################### + +The `%createDFBitmap()` macro allows to generate +a `dynamic function bitmap` which is a FCMP based +approach to create *dynamically* allocated **numeric** +bitmnap. + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +The idea of a SAS bitmap is based on: +1. SGF Paper 3101-2019 + titeled **Re-Mapping A Bitmap** by *Paul M. Dorfman* and *Lessia S. Shajenko* + [https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2019/3101-2019.pdf](https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2019/3101-2019.pdf) +2. SUGI Paper 8-26 + titeled **Table Look-Up by Direct Addressing: Key-Indexing -- Bitmapping -- Hashing** by *Paul M. Dorfman* + [https://support.sas.com/resources/papers/proceedings/proceedings/sugi26/p008-26.pdf](https://support.sas.com/resources/papers/proceedings/proceedings/sugi26/p008-26.pdf) + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDFBitmap( + bitmapName + <,debug=0> + <,outlib=work.DFAfcmp.package> + <,type=32> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `bitmapName` - *Required*, creates a FCMP call subroutine which is also + a bitmap name. In the data step it is used in form of + a call subroutine, e.g. `call bitmapName("Allocate", 3000)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `type=` - *Optional*, the default value is `32`. Sets the type of + bitwise operations executed internaly on the bitmap. + The only valid values are `32` or `52`, + With 32 the `BOR()` and `BAND()` SAS functions are used + and with 52 the `bit64orDFA()` and `bit64and DFA()` FCMP + functions are used. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &bitmapName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `Check`, `Test`, `T` - to get information if a bit is set to 1 (on) or not, + - `On`, `1` - to set a selected bit to 1, + - `Off`, `0` - to set a selected bit to 0, + - `C`, `Clear` - to reduce a bitmat to a single empty cell, + - `A`, `Allocate` - to reserve space for a bitmap and set all bits to 0, + - `A0`, `Allocate0` - to reserve space for a bitmap and set all bits to 0, + - `A1`, `Allocate1` - to reserve space for a bitmap and set all bits to 1, + - `D`, `Dim`, `Dimension` - to returns minimal and maximal index of the bitmap. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `On`, `Off`, `1`, `0`/ `Check`, `Test`, `T` it is a bitmap index, + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` sets the value of the minposition, i.e. the minimal position of the bitmap index, + - for `D`, `Dimension` it returns value of the minposition, + +.3 `value` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `Check`, `Test`, `T` it holds value retrieved from a bitmap on a given position, + - for `On`, `Off`, `1`, `0`, `C`, `Clear` is ignored, + - for `A`, `Allocate` it sets the value of the maxposition, i.e. maximal position of the array index, + - for `D`, `Dimension` it returns value of the maxposition + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Bitmap of type 32: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBitmap32,type=32,debug=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + call MyBitmap32("Allocate", -10, 100); + L = 0; H = 0; + call MyBitmap32("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H by 2; + put i @; + call MyBitmap32("1", i, .); + end; + put; + + * get values from the array ; + Value = .; + do i = L to H; + call MyBitmap32("T", i, Value); + put i= Value=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 2.** Bitmap of type 52: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBitmap52,type=52,debug=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + call MyBitmap52("Allocate", -10, 100); + L = 0; H = 0; + call MyBitmap52("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H by 2; + put i @; + call MyBitmap52("1", i, .); + end; + put; + + * get values from the array ; + Value = .; + do i = L to H; + call MyBitmap52("T", i, Value); + put i= Value=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 3.** Execution time test for type 52: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBigBitmap52,type=52,debug=0); + options FULLSTIMER APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example3; + call MyBigBitmap52("Allocate", -10, 2000000001); + L = 0; H = 0; + call MyBigBitmap52("Dim", L, H); + put L= H=; + + * populate bitmap with data ; + t = time(); + do i = L to H by 17; + call MyBigBitmap52("1", i, .); + x + 1; + end; + t = time() - t; + put "populate:" t= x=; + + * get values from the bitmap ; + t = time(); + Value = .; + do i = L to H; + call MyBigBitmap52("T", i, Value); + x + (-Value); + end; + t = time() - t; + put "search:" t= x=; + run; + +%* +L=-10 H=2000000001 +populate:t=55.902999878 x=117647060 +search:t=654.12900019 x=0 +NOTE: The data set WORK.EXAMPLE3 has 1 observations and 6 variables. +NOTE: DATA statement used (Total process time): + real time 11:50.42 + user cpu time 11:46.40 + system cpu time 0.45 seconds + memory 301791.12k + OS Memory 326332.00k +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 4.** Execution time test for type 32: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBigBitmap32,type=32,debug=0); + options FULLSTIMER APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example4; + call MyBigBitmap32("Allocate", -10, 2000000001); + L = 0; H = 0; + call MyBigBitmap32("Dim", L, H); + put L= H=; + + * populate bitmap with data ; + t = time(); + do i = L to H by 17; + call MyBigBitmap32("1", i, .); + x + 1; + end; + t = time() - t; + put "populate:" t= x=; + + * get values from the bitmap ; + t = time(); + Value = .; + do i = L to H; + call MyBigBitmap32("T", i, Value); + x + (-Value); + end; + t = time() - t; + put "populate:" t= x=; + run; + +%* +L=-10 H=2000000001 +populate:t=50.417999983 x=117647060 +populate:t=611.13600016 x=0 +NOTE: The data set WORK.EXAMPLE4 has 1 observations and 6 variables. +NOTE: DATA statement used (Total process time): + real time 11:02.07 + user cpu time 10:59.07 + system cpu time 1.46 seconds + memory 489583.90k + OS Memory 513876.00k +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `generateArrays` exec: <<< ####################### + +The generateArrays exec file provides a **list of automatically generated examples** of functions +emulating data structures. + +The list of provided examples is the following: +- `SmpArray` - Simple Immutable Dynamic Function Array +- `SmpMtbArray` - Simple Mutable Dynamic Function Array +- `SrchArray` - Searchable Immutable Dynamic Function Array +- `SrchMtbArray` - Searchable Mutable Dynamic Function Array +- `DynArrayC` - Dynamic Hash-based Character Function Array (length 256 bytes) +- `StackC` - Dynamic Hash-based Character Stack (length 256 bytes) +- `StackN` - Dynamic Hash-based Numeric Stack +- `FifoC` - Dynamic Hash-based Character Fifo (length 256 bytes) +- `FifoN` - Dynamic Hash-based Character Fifo +- `DescStackC` - Dynamic Hash-based Character Descending Ordered Stack (length 256 bytes) +- `AscStackC` - Dynamic Hash-based Character Ascending Ordered Stack (length 256 bytes) +- `DescStackN` - Dynamic Hash-based Numeric Descending Ordered Stack +- `AscStackN` - Dynamic Hash-based Numeric Ascending Ordered Stack +- `PrtQueueNTC` - Dynamic Hash-based Character Priority Queue with *New on Top* (length 256 bytes) +- `PrtQueueNBC` - Dynamic Hash-based Character Priority Queue with *New on Bottom* (length 256 bytes) +- `PrtQueueNTN` - Dynamic Hash-based Numeric Priority Queue with *New on Top* +- `PrtQueueNBN` - Dynamic Hash-based Numeric Priority Queue with *New on Bottom* +- `Bitmap32` - Dynamic Function Bitmap on 32 bit +- `Bitmap52` - Dynamic Function Bitmap on 52 bit + +The `outlib=` option is set to `work.DFAfcmp.package`. The `cmplib=` option is updated automatically. + +--- +## >>> `generateArrays` clean: <<< ####################### + +The generateArrays clean file clears the list of automatically generated examples of functions +emulating data structures provided in the `generatearrays.sas` exec file. + +The `cmplib=` option is updated automatically. + +--- + +## License #################################################################### + +Copyright (c) 2019 Bartosz Jablonski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- diff --git a/hist/0.5.6/dfa.zip b/hist/0.5.6/dfa.zip new file mode 100644 index 0000000000000000000000000000000000000000..c189a62bfead338dde1676f6ceb42e13e7f086bf GIT binary patch literal 48503 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Ɓk_&1!3+;_8;U2bClf8K-_qY8@iG`Xns@I#5g` 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 literal 0 HcmV?d00001