From 6f53d3ea6092f889e770b4311268c1e9506623b2 Mon Sep 17 00:00:00 2001 From: Aarush Bhat Date: Wed, 14 Feb 2024 16:49:22 +0530 Subject: [PATCH] =?UTF-8?q?uniquemask(=E2=89=A0)=20tests=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add basic uniquemask tests * add empty tests * add variation for shape * add shuffled data tests * add cross datatype tests * updates to cross data type tests * add comparision tollerance tests * add code coverage focused tests * add blog style docs on how to write tests * Update contributing.md * refactored how-to-add-tests.md * spelling errors * add model function docs to the how to write tests blog * fix formating * update contributing.md with howtowritetests blog url * new model for unique mask * use the util functions * add code coverage focused tests * use the same code coverage case for unique * add decision docs with the big cc explaination --- assets/unique-email.png | Bin 0 -> 35254 bytes contributing.md | 33 ++-- .../non-scalar-selection.md | 43 +++++ .../non-scalar-selector.md | 4 +- .../scalar-dyadic-arithmetic.md | 2 +- docs/how-to-add-tests.md | 174 +++++++++++++++++ tests/floor.apln | 6 +- tests/indexof.apln | 2 +- tests/membership.apln | 4 +- tests/residue.apln | 4 +- tests/unique.apln | 30 +-- tests/uniquemask.apln | 182 ++++++++++++++++++ 12 files changed, 443 insertions(+), 41 deletions(-) create mode 100644 assets/unique-email.png create mode 100644 docs/decision/primitive-functions/non-scalar-selection.md create mode 100644 docs/how-to-add-tests.md create mode 100644 tests/uniquemask.apln diff --git a/assets/unique-email.png b/assets/unique-email.png new file mode 100644 index 0000000000000000000000000000000000000000..0e161bbb800810c65f08d7a635233e74fcd926de GIT binary patch literal 35254 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 e|L0TvA7CMjtoI=S0X$%zMOs{5tWxCr&;JWsFP +Ullu tests the primitives one by one, covering all the code written in the sources of Dyalog APL, all possible cases, including edge cases, and all types of inputs it can receive. -A workflow demonstration blog on how to write tests is upcomming. Progress can be tracked [here](https://github.com/Dyalog/ullu/issues/50) - - - - +A workflow demonstration blog on how to write tests is present in [docs/how-to-add-tests.md](https://github.com/Dyalog/ullu/blob/main/docs/how-to-add-tests.md) ## Contributing Docs ### Decision docs -Decision Docs are records detailing key decisions, fostering transparency and aiding future collaboration by providing a structured account of the decision-making process. Documentation about why certain decisions were taken in the codebase, it basically explains the mindset of the developer writing the tests and it also documents all the anomalies in the codebase. +Decision Docs are records for detailing key decisions, fostering transparency and aiding future collaboration by providing a structured account of the decision-making process. Documenting why certain decisions were taken in the codebase, they explain the mindset of the developer writing the tests and also help document any anomalies in the codebase. It can be found [here](https://github.com/Dyalog/ullu/tree/docs-revamp/docs/decision) -In the decision docs, you need to mention the types of test cases included in the tests, description of all the variations of the tests and all the edge cases that were faced/handled. It needs to have all the information that a person in the future would need to expand the same tests or write new related ones. All the decisions taken while writing the tests. +In the decision docs, you need to mention the types of test cases included in the tests, a description of all the variations of the tests, and all the edge cases that were faced/handled. It needs to have all the information that a person in the future would need to expand on the same tests or write new related ones. -Decision docs for the primitive Magnitude are a good example of this. It can be found [here](https://github.com/Dyalog/ullu/blob/docs-revamp/docs/decision/primitive-functions/scalar-monadic.md#magnitude-rydocs) +Decision docs for the primitive Magnitude are a good example of this. They can be found [here](https://github.com/Dyalog/ullu/blob/docs-revamp/docs/decision/primitive-functions/scalar-monadic.md#magnitude-rydocs) --- -Note: By submitting a PR you agree to license your contribution under the ullu’s MIT [license](https://github.com/Dyalog/ullu/blob/main/LICENSE) unless explicitly noted otherwise. \ No newline at end of file +Note: By submitting a PR you agree to license your contribution under the ullu’s MIT [license](https://github.com/Dyalog/ullu/blob/main/LICENSE) unless explicitly noted otherwise. diff --git a/docs/decision/primitive-functions/non-scalar-selection.md b/docs/decision/primitive-functions/non-scalar-selection.md new file mode 100644 index 0000000..29be9c9 --- /dev/null +++ b/docs/decision/primitive-functions/non-scalar-selection.md @@ -0,0 +1,43 @@ +# Non Scalar Selection functions + +## Unique (`R←∪Y`)([docs](https://help.dyalog.com/latest/#Language/Primitive%20Functions/Unique.htm)) +Same as unqiue mask below + +## Unique Mask (`R←≠Y`)([docs](https://help.dyalog.com/latest/#Language/Primitive%20Functions/Unique%20Mask.htm)) + +Most of it is very similar to other tests so only documenting the different parts here. One thing that bugged me for a very long time was a switch case at `allos/src/same.c.html#L1311` in function `tolerant_nubsieve(void)` where the lines of code were not hit with a the normal cases. + +Exerpt from ROS's email: + +``` +This wasn’t easy to figure out ☹ + +I think the important factors here are the leading shape (“s”) of the array, and the number of unique elements (“u”). This creates such a thing: + +s 2⍴?u⍴0 + +(It assumes two identical random floats won’t be created, which is nearly but not quite safe to do.) + +Now, the cluster index seems to be a vector with a length s and range of values dependent on u. + +The grade-up index of the cluster index will also have a length s, but s unique values. + +ct is the element type of the cluster index, so its (squeezed) type is dependent on the number of unique values. It appears it can be Boolean or 1, 2 or 4 bytes (unsigned), encoded 1, 2, 3 or 4 (referred in big switch statement as APLBOOL, APLSINT, APLINTG and APLLONG, but that’s misleading because those are signed). + +gt is the element type of the grade-up index, so its squeezed type is dependent on the leading shape. It can be 1, 2 or 4 bytes (unsigned), encoded 2, 3 or 4 (APLSINT, APLINTG, APLLONG) + +This gives the possible combinations (ignore the colouring for now): +``` +![unique email](../../../assets/unique-email.png) +``` +However, there can’t be more unique elements than elements, so I think the red lines are impossible. + +Also, it appears that the generated cluster index doesn’t necessarily consist of the smallest element type – in particular, if gt is APLLONG then ct is always APLLONG too. That makes the orange lines impossible. + +You can get the remaining ones (those in black) by evaluating ≠s 2⍴?u⍴0, for the values u and s in the table. + +(You can also test the orange cases by squeezing the value you get back from cluster_index(), but that’s not something you can do in a “standard” interpreter.) + +Regards, +Richard +``` \ No newline at end of file diff --git a/docs/decision/primitive-functions/non-scalar-selector.md b/docs/decision/primitive-functions/non-scalar-selector.md index c452b42..0e93ba2 100644 --- a/docs/decision/primitive-functions/non-scalar-selector.md +++ b/docs/decision/primitive-functions/non-scalar-selector.md @@ -5,7 +5,7 @@ The tests include: - Datatype tests: tests for found and indexed/not-found variations for all the available datatypes - Cross-datatype tests: tests for found and indexed/not-found across datatypes, concatenating expressions and results to find any errors. -- Tests based on Comparision tolerance(`⎕CT` & `⎕DCT`): tests to check if `d=d+1` on larger values of double, floating and complex numbers based on comparision tolerance values(default or 0). +- Tests based on comparison tolerance(`⎕CT` & `⎕DCT`): tests to check if `d=d+1` on larger values of double, floating and complex numbers based on comparison tolerance values(default or 0). - Tests based on Floating point representation(`⎕FR`): All the tests run with values of `⎕FR` as 645 and 1287. - Separate tests for boolean values: Booleans need special tests because they only have 2 elements and since `i1` and `bool` have overlapping values. @@ -23,7 +23,7 @@ Code Coverage report: NA The tests include: - Datatype tests: tests for found/not-found variations for all the available datatypes. - Cross-datatype tests: tests for found/not-found across datatypes, concatenating expressions and results to find any errors. -- Tests based on Comparision tolerance(`⎕CT` & `⎕DCT`): tests to check if `d=d+1` on larger values of double, floating and complex numbers based on comparision tolerance values(default or 0). +- Tests based on comparison tolerance(`⎕CT` & `⎕DCT`): tests to check if `d=d+1` on larger values of double, floating and complex numbers based on comparison tolerance values(default or 0). - Tests based on Floating point representation(`⎕FR`): All the tests run with values of `⎕FR` as 645 and 1287. - Separate tests for boolean values: Booleans need special tests because they only have 2 elements and since `i1` and `bool` have overlapping values. diff --git a/docs/decision/primitive-functions/scalar-dyadic-arithmetic.md b/docs/decision/primitive-functions/scalar-dyadic-arithmetic.md index 5b5872c..d956b31 100644 --- a/docs/decision/primitive-functions/scalar-dyadic-arithmetic.md +++ b/docs/decision/primitive-functions/scalar-dyadic-arithmetic.md @@ -5,7 +5,7 @@ The tests include: - Datatype tests: tests for positive and negative for all the available numeric datatypes - Tests based on Floating point representation(`⎕FR`): All the tests run with values of `⎕FR` as 645 and 1287. -- Tests based on Comparison Tollerance(`⎕CT` and `⎕DCT`): All the tests run with default and zero values. +- Tests based on Comparison tolerance(`⎕CT` and `⎕DCT`): All the tests run with default and zero values. - Edge Cases: - Separate cases had to be added for 0, ¯1, 0J0, 0.0 - Separate cases had to be added to residue propogated using a scan to target certain sections of sources. diff --git a/docs/how-to-add-tests.md b/docs/how-to-add-tests.md new file mode 100644 index 0000000..991f9bc --- /dev/null +++ b/docs/how-to-add-tests.md @@ -0,0 +1,174 @@ +# How to add tests + +### Make a namespace + +Make a namespace titled the primitive being tested + +Eg: uniquemask + +```APL +:Namespace uniquemask + ⍝... +:EndNamespace +``` + +### Main function + +Start with making the main function titled `test_functionname` like `test_uniquemask`. Here `test_` is important because the `./unittest.apln` recognises the main function of the test suite of the primitive with the `test_` keyword. + +### Initialise variables + +Primitives depend on ⎕CT/⎕DCT, ⎕FR and ⎕IO, so all default values of these can be initialised: + +```APL +ct_default←1E¯14 +dct_default←1E¯28 +fr_dbl←645 +fr_decf←1287 +io_default←1 +io_0←0 +``` + +Then we need to get some specific data that we can manipulate to give us expected results to some testcases to logically/mathematically check the correct output. This is meant as a very basic fallback for testing with model functions fail. + +This can look something like this: + +This is an example from [unique mask](tests\uniquemask.apln) (≠) + +```APL +⍝ All data generated is unique +bool←0 1 ⍝ 11: 1 bit Boolean type arrays +i1←¯60+⍳120 ⍝ 83: 8 bits signed integer +char1←⎕UCS (100+⍳100) ⍝ 80: 8 bits character +char2←⎕UCS (1000+⍳100) ⍝ 160: 16 bits character +i2←{⍵,-⍵}10000+⍳100 ⍝ 163: 16 bits signed integer +char3←⎕UCS (100000+⍳100) ⍝ 320: 32 bits character +i3←{⍵,-⍵}100000+⍳100 ⍝ 323: 32 bits signed integer +ptr←(13↑⎕a) (13↓⎕a) ⍝ 326: Pointer (32-bit or 64-bit as appropriate) +dbl←{⍵,-⍵}i3+0.1 ⍝ 645: 64 bits Floating +cmplx←{⍵,-⍵}(0J1×⍳100)+⌽⍳100 ⍝ 1289: 128 bits Complex +Hcmplx←{⍵,-⍵}(1E14J1E14×⍳20) ⍝ 1289 but larger numbers to test for CT value +⍝ Hdbl is 645 but larger numbers to test for CT value +⍝ intervals of 2 are chosen because CT for these numbers +1 and -1 +⍝ come under the region of tolerant equality +Hdbl←{⍵,-⍵}1E14+(2×⍳50) + +⍝ This is needed for a case that can be hit if we have a lot of small numbers +⍝ which produce a hash collision +⍝ Occurrence: same.c.html#L1153 +Sdbl←{⍵,-⍵}(⍳500)÷1000 + +⍝ Hfl is 1287 but larger numbers to test for CT value +⍝ far intervals are chosen for non overlap +⍝ with region of tolerant equality +⎕FR←fr_decf +fl←{⍵,-⍵}i3+0.01 ⍝ 1287: 128 bits Decimal +Hfl←{⍵,-⍵}2E29+(1E16×⍳10) +⎕FR←fr_dbl +``` + +### Initialise test description + +Test description gives information about the `testID`, datatypes being tested on, the [test variaiton](todo: add link to variation section), and the different setting values. + +```APL +testDesc←{'for ',case,{0∊⍴case2:'',⍵⋄' , ', case2,⍵},' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR, '& ⎕IO:', ⎕IO} +``` + +### Testing functions + +#### `Assert` + +Assert is a function described in `./unittest.apln` that takes in a test expression that gives a boolean result and evaluates the output of the result and gives the instructions to pretty print the result based on the user settings of the test suite. + +#### `RunVariations` + +RunVariations is a function described in each test file which takes the expressions to be evaluated and does the following: +- tests using the standard form it comes in +- tests a scalar element from the data it gets +- tests an empty array derived from the input +- applies a different shape to the input and evaluates +- creates a different shape that has a 0 in the shape of the input + +#### Model function + +A model function replicates the behavior of an existing function by employing alternative primitives or computational steps. Model functions are used to test outputs of tests that can give not very intuitively computable results. Model functions here try to use primitives that are least related to the primitive being tested(this is mainly related so that it can be easily pin pointed which primitive is failing because shared code can be difficult to deal with). Model functions look like: + +```APL + modelMagnitude←{⍵×(¯1@(∊∘0)(⍵>0))} +``` + +```APL + modelUnique←{0=≢⍵:⍵ ⋄ ↑,⊃{⍺,(∧/⍺≢¨⍵)/⍵}⍨/⌽⊂¨⊂⍤¯1⊢⍵} +``` + +### The tests + +All tests should run with all types of ⎕CT/⎕DCT, ⎕FR and ⎕IO values depending on which settings are implicit arguments of the primitive, ie. all of the settings that they depend on. +```APL +:For io :In io_default io_0 + ⎕IO←io + + :For ct :In 1 0 + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance + + :For fr :In fr_dbl fr_decf + ⍝ ... + :EndFor + :EndFor +:EndFor +``` + +#### Types of tests + +The general structure followed with all tests is as follows: + +##### General tests + +General tests are tests that test information other than if the primitive gives the correct output. Some examples of uniquemask: + +- uniquemask cannot return a result that exceeds the number of elements of the input + ```APL + r,← 'TGen1' desc Assert (≢data)≥≢≠data + ``` + +- datatype of the result will always be boolean in nature + ```APL + r,← 'TGen2' desc Assert 11≡⎕dr ≠data intertwine data ⍝ intertwine is a util function that intertwines the data like (1 1 1 1) intertwine (0 0 0 0) gives 1 0 1 0 1 0 1 0 + ``` + +##### Logical/mathematical tests + +These are tests that evaluate the result of the primitive with a very logical straightforward approach and try to depend on as few primitives as possible to reduce the number of false failures if the dependent primitives fail. Some examples of unique mask: + +- all elements of data are unique so the result would be all 1s + ```APL + r,← 'T1' desc RunVariations (1⍨¨data) data + ``` + +- all elements are perfectly intertwined so the result would be 1 0 1 0 1 0... + ```APL + r,← 'T3' desc RunVariations ((1⍨¨data) intertwine (0⍨¨data)) (data intertwine data) + ``` + +##### Cross datatype tests + +Cross data type tests deal with the primitive handling 2 datatypes at a time in the same input. Each datatype must be tested with every other datatype for a more accurate result. + +##### comparison tolerance tests + +Comparison tolerance tests deal with the primitive getting inputs which are believed to be in the tolerance range of numbers. The inputs are generally numbers slightly bigger and smaller than the original number that is treated to be equal at default ⎕CT and ⎕DCT values and should be treated differently when ⎕CT and ⎕DCT are zero. + +More information about comparison tolerance here: https://help.dyalog.com/latest/Content/Language/System%20Functions/ct.htm + +and here: https://www.dyalog.com/uploads/documents/Papers/tolerant_comparison/tolerant_comparison.htm + +##### Independent tests + +Independent tests are tests for special cases that either have optimisations in the sources or have a special need that cannot be covered in general data types and only work on certain specific values. For example: +- The special case can be hit if we have two 8 bit int numbers in the input: a & b, and a is b-⎕CT. That means, that when we get to element b in the loop, we will find element a and hit the case. +Occurrence: same.c.html#L1152 + ```APL + d←i1[?≢i1] + r,←'TCTI1' desc Assert (1 0)≡(≠ (d-({fr-1:⎕dct⋄⎕ct}⍬)) d) + ``` diff --git a/tests/floor.apln b/tests/floor.apln index 6e40d05..f47460b 100644 --- a/tests/floor.apln +++ b/tests/floor.apln @@ -95,7 +95,7 @@ testDesc←{'for ',case,{0∊⍴case2:'',⍵⋄' , ', case2,⍵},' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR} :For ct :In 0 1 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In 2 1 ⎕FR←fr⊃fr_dbl fr_decf ⍝ set type of floating-point computations :For case :In 'zero' 'bool' 'i1' 'i2' 'i3' 'dbl' 'fl' 'Hdbl' 'Hfl' @@ -124,7 +124,7 @@ r,← 'TDbl' desc RunVariations ({(⍵-0.5),0,-0.5+⍵}(halfLen↑data)) data ⍝ floor of dbl is removing the 0.5 from the number :EndIf - ⍝ tests with comparision tolerance + ⍝ tests with comparison tolerance d1←data[?≢data] almostd1←d1×1-fr⊃1E¯2×ct_default dct_default ⍝ infinitesimally close to d1 but smaller :If ct ⍝ tolerant @@ -174,7 +174,7 @@ testDesc←{'for ',case,' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR} :For ct :In 0 1 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In 1 2 ⎕FR←fr⊃fr_dbl fr_decf :For case :In 'cmplx' 'Hcmplx' diff --git a/tests/indexof.apln b/tests/indexof.apln index de2c5cd..ee3a868 100644 --- a/tests/indexof.apln +++ b/tests/indexof.apln @@ -75,7 +75,7 @@ ⎕IO←io :For ct :In 1 0 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In fr_dbl fr_decf ⎕FR←fr diff --git a/tests/membership.apln b/tests/membership.apln index 37fd5c9..5e53af5 100644 --- a/tests/membership.apln +++ b/tests/membership.apln @@ -74,7 +74,7 @@ testDesc←{'for ',case,{0∊⍴case2:'',⍵⋄' , ', case2,⍵},' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR} :For ct :In 1 0 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In 1 2 ⎕FR←fr⊃fr_dbl fr_decf @@ -107,7 +107,7 @@ r,← 'T3' desc RunVariations (1⍨¨data) data data ⍝ all elements return 1 r,← 'T4' desc RunVariations 0 5E50 data ⍝ huge element outside set is not found - ⍝ tests with comparision tolerance + ⍝ tests with comparison tolerance d←data[?≢data] :If ct ⍝ tolerant :If (⊂data)∊Hdbl Hfl Hcmplx diff --git a/tests/residue.apln b/tests/residue.apln index ffba2ec..49fd03e 100644 --- a/tests/residue.apln +++ b/tests/residue.apln @@ -57,7 +57,7 @@ testDesc←{'for ',case,{0∊⍴case2:'',⍵⋄' , ', case2,⍵},' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR} :For ct :In 0 1 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In 2 1 ⎕FR←fr⊃fr_dbl fr_decf @@ -109,7 +109,7 @@ r,← 'TSeqDbl2' desc RunVariations ({⍵,0,(2↓⌽⍵),0.5,9.5}halfLen⍴(0.5+⍳9), 0.5) 10 data ⍝ sequences to test functionality of residue :EndIf - ⍝ tests with comparision tolerance + ⍝ tests with comparison tolerance almostd1←d1×1-fr⊃1E¯2×ct_default dct_default ⍝ infinitesimally close to d1 but smaller :If ct ⍝ tolerant :If (⊂data)∊Hdbl Hfl Hcmplx ⍝ bigger numbers diff --git a/tests/unique.apln b/tests/unique.apln index 30bae2f..e92a143 100644 --- a/tests/unique.apln +++ b/tests/unique.apln @@ -19,10 +19,11 @@ ⍝ scalar ele←(?∘≢⊃⊢)rarg - actualRS←∪ele - tRes,←('Scalar',tID) tCmt Assert (,ele)≡actualRS + actualRSc←∪ele + expectedRSc←,ele + tRes,←('Scalar',tID) tCmt Assert expectedRSc≡actualRSc - ⍝ ⍝ empty + ⍝ empty actualRE←∪0⍴rarg ⍝ 0 in the shape means we have no elements in the array, i.e. it's empty. expectedRE←0∘⌿expectedR ⍝ empty array along first axis tRes,←('Empty',tID) tCmt Assert expectedRE≡actualRE ⍝ empty array is expectedR @@ -84,11 +85,18 @@ desc←testDesc⍬ :For ct :In 0 1 - (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparision tolerance + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance :For fr :In 2 1 ⎕FR←fr⊃fr_dbl fr_decf - desc←testDesc⍬ + + ⍝ Independant code coverage based (more information in decision docs) + :For (u s) :In (2 10) (2 256) (10 10) (10 256) (256 256) (65536 65536) + case←u s + desc←testDesc⍬ + x←s 2⍴?u⍴0 + r,←'TICC1' desc Assert (model x)≡(∪x) + :EndFor :For case :In 'bool' 'i1' 'i2' 'i3' 'char1' 'char2' 'char3' 'ptr' 'dbl' 'fl' 'cmplx' 'Hdbl' 'Sdbl' 'Hfl' 'Hcmplx' data←⍎case @@ -117,19 +125,19 @@ case2←⍬ ⍝ dispose case2 desc←testDesc⍬ - r,← 'T1' desc RunVariations data data ⍝ all elements of data are indexed - r,← 'T2' desc RunVariations data (2/data) ⍝ all elements of data are repeated sequentially + r,← 'T1' desc RunVariations data data ⍝ all elements of data are unique + r,← 'T2' desc RunVariations data (data,data) ⍝ all elements of data are repeated sequentially r,← 'T3' desc RunVariations data (data intertwine data) ⍝ all elements are perfectly intertwined r,← 'T4' desc RunVariations data (hashArray data intertwine data) ⍝ using a pre-hashed array on intertwined data shuffledData←↑shuffle data - r,← 'T4' desc RunVariations (model shuffledData) shuffledData ⍝ shuffle data without creating duplicate data + r,← 'T5' desc RunVariations (model shuffledData) shuffledData ⍝ shuffle data without creating duplicate data repetitions←?6 shuffledRepeatedData←↑shuffle repetitions/data - r,← 'T5' desc RunVariations (model shuffledRepeatedData) shuffledRepeatedData ⍝ duplicate and shuffle + r,← 'T6' desc RunVariations (model shuffledRepeatedData) shuffledRepeatedData ⍝ duplicate and shuffle - ⍝ tests with comparision tolerance + ⍝ tests with comparison tolerance :If ~(⎕DR data) ∊ 80 160 320 326 ⍝ non-numeric are skipped d1←(data~0)[?≢data~0] ⍝ 0 interferes with the calculations of almostd1S and almostd1B hence it is removed almostd1S←d1×1-fr⊃1E¯2×ct_default dct_default ⍝ infinitesimally close to d1 but smaller @@ -162,7 +170,7 @@ r,←'TboolI1' desc Assert (,0)≡∪2/∧/1 0 1 0 r,←'TboolI2' desc Assert (,1)≡∪2/∧/1 1 1 1 - ⍝ The special case can be hit if we have two 8 bit int numbers in the input: a & b, and a is b×1-⎕CT. + ⍝ The special case can be hit if we have two 8 bit int numbers in the input: a & b, and a is b-⎕CT. ⍝ That means, that when we get to element b in the loop, we will find element a and hit the case. ⍝ Occurrence: same.c.html#L1152 d←i1[?≢i1] diff --git a/tests/uniquemask.apln b/tests/uniquemask.apln new file mode 100644 index 0000000..bc0ad87 --- /dev/null +++ b/tests/uniquemask.apln @@ -0,0 +1,182 @@ +:Namespace uniquemask + Assert←#.unittest.Assert + ⍝ util functions + shuffle←#.utils.shuffle + intertwine←#.utils.intertwine + hashArray←#.utils.hashArray + + ⍝ model ← { ⍝ from aplwiki nubsieve page ⍝ does not work if shape has a 0 + ⍝ ⎕IO←0 + ⍝ notin ← (⍳=≢⍤⊣)⍨ + ⍝ x ← 1/⍵ ⍝ Treat scalar as vector + ⍝ m ← ⍬ ⍝ Initial mask + ⍝ m ⊣ {m,←(⍵⌷x) notin m⌿⍵↑x}¨ ⍳≢x + ⍝ } + modelUnique←{0=≢⍵:⍵ ⋄ ↑,⊃{⍺,(∧/⍺≢¨⍵)/⍵}⍨/⌽⊂¨⊂⍤¯1⊢⍵} ⍝ from tests/unique.apln + model←(⍳⍤≢=⍳⍨)⍤(modelUnique⍳1/⊢) + + ∇ tRes←tData RunVariations exp ;actualR;actualRE;expectedR;expectedRE;ele;rarg;tID;tCmt;shape;actualRS;shapeW0;actualRSW0;expectedRS;expectedRSW0 + (expectedR rarg)←exp + (tID tCmt)←tData + tRes←⍬ + + ⍝ normal + actualR←≠rarg + tRes,←tData Assert expectedR≡actualR + + ⍝ scalar + ele←(?∘≢⊃⊢)rarg + actualRSc←≠ele + expectedRSc←(,1⍨¨ele) + tRes,←('Scalar',tID) tCmt Assert expectedRSc≡actualRSc + + ⍝ empty + actualRE←≠0⍴rarg ⍝ 0 in the shape means we have no elements in the array, i.e. it's empty. + expectedRE←0∘⌿expectedR ⍝ empty array along first axis + tRes,←('Empty',tID) tCmt Assert expectedRE≡actualRE ⍝ empty array is expectedR + + ⍝ different shapes + shape←?(?4)/4 + actualRS←≠(shape⍴rarg) + expectedRS←model shape⍴rarg + tRes,←('Multiple',tID) tCmt Assert expectedRS ≡ actualRS + + ⍝ different shapes with 0 in shape + shapeW0←(0@(?(≢shape)))shape + actualRSW0←≠shapeW0⍴rarg + expectedRSW0←model shapeW0⍴rarg + tRes,←('ShapeW0',tID) tCmt Assert expectedRSW0 ≡ actualRSW0 + ∇ + + ∇ r←test_uniquemask + ct_default←1E¯14 + dct_default←1E¯28 + fr_dbl←645 + fr_decf←1287 + + ⍝ All data generated is unique + bool←0 1 ⍝ 11: 1 bit Boolean type arrays + i1←¯60+⍳120 ⍝ 83: 8 bits signed integer + char1←⎕UCS (100+⍳100) ⍝ 80: 8 bits character + char2←⎕UCS (1000+⍳100) ⍝ 160: 16 bits character + i2←{⍵,-⍵}10000+⍳100 ⍝ 163: 16 bits signed integer + char3←⎕UCS (100000+⍳100) ⍝ 320: 32 bits character + i3←{⍵,-⍵}100000+⍳100 ⍝ 323: 32 bits signed integer + ptr←(13↑⎕a) (13↓⎕a) ⍝ 326: Pointer (32-bit or 64-bit as appropriate) + dbl←{⍵,-⍵}i3+0.1 ⍝ 645: 64 bits Floating + cmplx←{⍵,-⍵}(0J1×⍳100)+⌽⍳100 ⍝ 1289: 128 bits Complex + Hcmplx←{⍵,-⍵}(1E14J1E14×⍳20) ⍝ 1289 but larger numbers to test for CT value + ⍝ Hdbl is 645 but larger numbers to test for CT value + ⍝ intervals of 2 are chosen because CT for these numbers +1 and -1 + ⍝ come under the region of tolerant equality + Hdbl←{⍵,-⍵}1E14+(2×⍳50) + + ⍝ This is needed for a case that can be hit if we have a lot of small numbers + ⍝ which produce a hash collision + ⍝ Occurrence: same.c.html#L1153 + Sdbl←{⍵,-⍵}(⍳500)÷1000 + + ⍝ Hfl is 1287 but larger numbers to test for CT value + ⍝ far intervals are chosen for non overlap + ⍝ with region of tolerant equality + ⎕FR←fr_decf + fl←{⍵,-⍵}i3+0.01 ⍝ 1287: 128 bits Decimal + Hfl←{⍵,-⍵}2E29+(1E16×⍳10) + ⎕FR←fr_dbl + + r←⍬ + testDesc←{'for ',case,{0∊⍴case2:'',⍵⋄' , ', case2,⍵},' & ⎕CT ⎕DCT:',⎕CT,⎕DCT, '& ⎕FR:', ⎕FR} + + case←⍬ + case2←⍬ + desc←testDesc⍬ + + :For ct :In 0 1 + (⎕CT ⎕DCT)←ct × ct_default dct_default ⍝ set comparison tolerance + + :For fr :In 2 1 + ⎕FR←fr⊃fr_dbl fr_decf + + ⍝ Independant code coverage based (more information in decision docs) + :For (u s) :In (2 10) (2 256) (10 10) (10 256) (256 256) (65536 65536) + case←u s + desc←testDesc⍬ + x←s 2⍴?u⍴0 + r,←'TICC1' desc Assert (model x)≡(≠x) + :EndFor + + :For case :In 'bool' 'i1' 'i2' 'i3' 'char1' 'char2' 'char3' 'ptr' 'dbl' 'fl' 'cmplx' 'Hdbl' 'Sdbl' 'Hfl' 'Hcmplx' + data←⍎case + desc←testDesc⍬ + + ⍝ General tests to test the basic rules of uniquemask + r,← 'TGen1' desc Assert (≢data)≥≢≠data ⍝ uniquemask cannot return a result that is exceding the number of elements than the input + r,← 'TGen2' desc Assert 11≡⎕dr ≠data intertwine data ⍝ datatype of the result will always be boolean + + :For case2 :In 'i1' 'i2' 'i3' 'char1' 'char2' 'char3' 'ptr' 'dbl' 'fl' 'cmplx' 'Hdbl' 'Hfl' 'Hcmplx' + data2←⍎case2 + ⍝ datatonot←((data{(≢⍺)<≢⍵:⍺⋄⍵}data2)) + desc←testDesc⍬ + :If (case≡case2) ∨ (case≡'bool') ⍝ skipping bool because of overlap with i1 + :Continue + :EndIf + r,← 'TCross1' desc RunVariations (1⍨¨data,data2) (data,data2) ⍝ all elements are concatenated + + ⍝ todo: needs fixing because of different lengths of data and data2 + ⍝ r,← 'TCross2' desc Assert ({2/(⍵/1) intertwine ⍵/0}2÷⍨+/≢¨data data2)≡≠((2/data) intertwine (2/data2)) ⍝ all elements are doubled & perfectly intertwined\ + + ⍝ datatype of the result will always be boolean + r,← 'TGen3' desc Assert 11≡⎕dr ≠data intertwine data2 + :EndFor + + case2←⍬ ⍝ dispose case2 + desc←testDesc⍬ + + r,← 'T1' desc RunVariations (1⍨¨data) data ⍝ all elements of data are unique + r,← 'T2' desc RunVariations ((1⍨¨data),0⍨¨data) (data,data) ⍝ all elements of data are repeated sequentially + r,← 'T3' desc RunVariations ((1⍨¨data) intertwine (0⍨¨data)) (data intertwine data) ⍝ all elements are perfectly intertwined + r,← 'T4' desc RunVariations ((1⍨¨data) intertwine (0⍨¨data)) (hashArray data intertwine data) ⍝ using a pre-hashed array on intertwined data + + shuffledData←↑shuffle data + r,← 'T5' desc RunVariations (model shuffledData) shuffledData ⍝ shuffle data without creating duplicate data + + repetitions←?6 + shuffledRepeatedData←↑shuffle repetitions/data + r,← 'T6' desc RunVariations (model shuffledRepeatedData) shuffledRepeatedData ⍝ duplicate and shuffle + + ⍝ tests with comparison tolerance + :If ~(⎕DR data) ∊ 80 160 320 326 ⍝ non-numeric are skipped + d1←(data~0)[?≢data~0] ⍝ 0 interferes with the calculations of almostd1S and almostd1B hence it is removed + almostd1S←d1×1-fr⊃1E¯2×ct_default dct_default ⍝ infinitesimally close to d1 but smaller + almostd1B←d1×1+fr⊃1E¯1×ct_default dct_default ⍝ infinitesimally close to d1 but bigger + :If ct ⍝ tolerant + :If (⊂data)∊Hdbl Hfl Hcmplx ⍝ bigger numbers + ⍝ Hdbl=Hdbl+1 with default CT, but not for DECF + r,← 'CTDefault1' desc Assert (((1 0)≡≠d1,d1+1) ∨ ((fr=2) ∧ case≡'Hdbl')) + :Else ⍝ other than bigger numbers + r,← 'CTDefault2' desc Assert ((1 1)≡≠d1,d1+1) ⍝ not tolerantly equal for other numbers + r,← 'CTDefaultAlmostS' desc Assert ((1 0)≡≠d1,almostd1S) ⍝ d1 and almostd1S are tolerantly equal + r,← 'CTDefaultAlmostB' desc Assert ((1 0)≡≠d1,almostd1B) ⍝ d1 and almostd1B are tolerantly equal + :EndIf + :Else ⍝ exact + ⍝ ⍝ d≠d+1 for all numeric types + r,← 'CTZero' desc Assert (((1,1)≡≠d1,d1+1) ∨ ((fr=1) ∧ case≡'Hfl')) + r,← 'CTZeroAlmostS' desc Assert (((1,1)≡≠d1,almostd1S) ∨ ((fr=2) ∧ 1289≡⎕dr d1)) ⍝ due to limited precision of IEEE 745 doubles cmplx is ignored with ⎕fr←1287 + r,← 'CTZeroAlmostB' desc Assert (((1,1)≡≠d1,almostd1B) ∨ ((fr=2) ∧ 1289≡⎕dr d1)) ⍝ due to limited precision of IEEE 745 doubles cmplx is ignored with ⎕fr←1287 + :EndIf + :EndIf + :EndFor + ⍝ Independant tests + case←'independant' + case2←⍬ + desc←testDesc⍬ + + ⍝ The special case can be hit if we have two 8 bit int numbers in the input: a & b, and a is b-⎕CT. + ⍝ That means, that when we get to element b in the loop, we will find element a and hit the case. + ⍝ Occurrence: same.c.html#L1152 + d←i1[?≢i1] + r,←'TCTI1' desc Assert (1 0)≡(≠ (d-({fr-1:⎕dct⋄⎕ct}⍬)) d) + :EndFor + :EndFor + ∇ +:EndNamespace