From 35f72f73226330abd7d53f6846ba7ba6e8b5ffcf Mon Sep 17 00:00:00 2001 From: Bart Jablonski Date: Tue, 17 Feb 2026 14:53:09 +0100 Subject: [PATCH] The DFA package, version: 0.5.10 The DFA package, version: 0.5.10 Package regenerated with the SAS Packages Framework, version 20260216. No functional changes, aesthetic documentation clean up. - File SHA256: `F*C1E5126D8EDE050A758BCB5DCCA56A37125B3646CE75F1CF41EDE00890901AD9` for this version - Content SHA256: `C*EE048846A8155C317867DCDB8EE1AE9E0352235DC247E4379D101A7296BD0C07` for this version --- README.md | 2 +- dfa.md | 14 +- dfa.zip | Bin 49267 -> 49229 bytes hist/0.5.10/dfa.md | 1699 +++++++++++++++++++++++++++++++++++++++++++ hist/0.5.10/dfa.zip | Bin 0 -> 49229 bytes 5 files changed, 1706 insertions(+), 9 deletions(-) create mode 100644 hist/0.5.10/dfa.md create mode 100644 hist/0.5.10/dfa.zip diff --git a/README.md b/README.md index 4df8691..ca26654 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*17C88537F5FA9BCFAA1AC4803D0F1EF47665C8446A44C82B5558A08315DF0C49 +SHA256 digest for the latest version of `DFA`: F*C1E5126D8EDE050A758BCB5DCCA56A37125B3646CE75F1CF41EDE00890901AD9 [**Documentation for DFA**](./dfa.md "Documentation for DFA") diff --git a/dfa.md b/dfa.md index df4a6cd..3ad97e2 100644 --- a/dfa.md +++ b/dfa.md @@ -9,23 +9,21 @@ ### Version information: - Package: DFA -- Version: 0.5.9 -- Generated: 2026-02-02T13:54:19 +- Version: 0.5.10 +- Generated: 2026-02-17T12:17:54 - Author(s): Bartosz Jablonski (yabwon@gmail.com) - Maintainer(s): Bartosz Jablonski (yabwon@gmail.com) - License: MIT -- File SHA256: `F*17C88537F5FA9BCFAA1AC4803D0F1EF47665C8446A44C82B5558A08315DF0C49` for this version -- Content SHA256: `C*1818B4D524F779F2FB3A242D9E5BEEB592074A92D68135E18A660E594B214401` for this version +- File SHA256: `F*C1E5126D8EDE050A758BCB5DCCA56A37125B3646CE75F1CF41EDE00890901AD9` for this version +- Content SHA256: `C*EE048846A8155C317867DCDB8EE1AE9E0352235DC247E4379D101A7296BD0C07` for this version --- -# The `DFA` package, version: `0.5.9`; +# The `DFA` package, version: `0.5.10`; --- -# The DFA package [ver. 0.5.9] ############################################### - The **DFA** (a.k.a. *Dynamic Function Array*) package implements: - dynamic numeric and character arrays, - dynamic stacks (filo), @@ -56,7 +54,7 @@ Required SAS Components: --------------------------------------------------------------------- -*SAS package generated by SAS Package Framework, version `20260202`,* +*SAS package generated by SAS Package Framework, version `20260216`,* *under `WIN`(`X64_10PRO`) operating system,* *using SAS release: `9.04.01M9P06042025`.* diff --git a/dfa.zip b/dfa.zip index 2b6cc222341576007e26b542988bf73a00103219..f10869ee87ca8d74ad1e8330ef60ca491ceacfb2 100644 GIT binary patch delta 10737 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 delta 10746 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 ###### + +## >>> `%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 ###### + +## >>> `%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 ###### + +## >>> `%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 ###### + +## >>> `%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 ###### + +## >>> `%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 ###### + +## >>> `%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; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `bit64andprotodfa()` proto ###### + +## >>> `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. + +--- + + +--- + +## `bit64orprotodfa()` proto ###### + +## >>> `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. + +--- + + +--- + +## `bit64anddfa()` function ###### + +## >>> `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; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `bit64ordfa()` function ###### + +## >>> `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; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdfbitmap()` macro ###### + +## >>> `%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 ###### + +## >>> `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 ###### + +## >>> `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 - 2026 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.10/dfa.zip b/hist/0.5.10/dfa.zip new file mode 100644 index 0000000000000000000000000000000000000000..f10869ee87ca8d74ad1e8330ef60ca491ceacfb2 GIT binary patch literal 49229 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 r{nvMfKaqalhx`-CtmSW{|Gq0xlmQ2