Skip to content

Instantly share code, notes, and snippets.

@abrudz
Created December 16, 2020 19:08
Show Gist options
  • Save abrudz/f3da258fbb70a1cf8cefea55cc76b207 to your computer and use it in GitHub Desktop.
Save abrudz/f3da258fbb70a1cf8cefea55cc76b207 to your computer and use it in GitHub Desktop.

Background

While the yearly get-togethers are called user meetings (previously known as conferences), I found that the social setting allowed Dyalog's staff to discuss and develop ideas in a way that would not happen in the office setting of Bramley.

I had a vague idea about an operator that would ease working with value tolerances and ranges. During our ride up Mount Etna, I by chance had the pleasure of sitting next to Geoff Streeter. We started discussing some things, and before long I had my laptop out and we were prototyping a new operator.

I discussed my idea with Nick Nickolov, who told me that being a fan of ⎕CT←0, he has considered to denote tolerant equality. I think we then naturally would want , and , and , and so on.. It is clear that we are dealing with a whole concept here, namely the allowing for deviation in comparisons.

There is a long-standing disagreement on whether ⎕CT is a mathematical concept of tolerance (Geoff Streeter's position) or just a patch for binary machines' problems with floating point calculations (Morten Kromberg's position). By introducing a specific operator to denote allowed range in comparison, even Geoff (he told me so!) would agree that ⎕CT remains nothing but a computing tool. ⎕CT would continue to apply in comparisons with allowed range, only further expanding the allowance, but the user could set ⎕CT←0 and use his own code to get exactly the precision he wants.

Later, I had the honour of discussing the idea in an informal group including Nick, Geoff, Aaron Hsu, Roger Hui, and other bright minds. During a meal, I also discussed the idea with Brian Becker. After drafting this blog post, Geoff came up with a significant improvement, which I could extend even further:

A whole aspect of tolerant comparison could easily be added to the proposed operator by allowing a vector right-operand, where the first element represents relative deviance (⎕CT style), and the second element represents absolute deviance. For example, =±0.1 2 would mean comparison with a deviance of up to 10% or 2 units. For 100 it would mean 90 ≤ x ≤ 110, for 10 it would mean 8 ≤ x ≤ 12, and for 0 it would mean −2 ≤ x ≤ 2. This solves the often encountered problem that ⎕CT is not used in comparisons with zero, and opens up applications like neutral joystick input with a bit of play.

Furthermore, the right-operand could be expanded to the complex domain allowing different deviance in the real and imaginary dimensions: 0 (=±0.1J0.1) f x flags all approximate roots of f, while 0 (=±0.1) f x flags only the real approximate roots.

Thought Concept

Consider the common notation* for a value with an allowed deviation, x = 1 ± 2 meaning −1 ≤ x ≤ 3.

Currently in Dyalog APL we have to use the rather cumbersome expression (¯1≤x)∧(x≤2) because the equality in essence is ternary (has three arguments; x, ¯1, and 2). Unfortunately, this APL expression is not a good tool for thought, because the ± really conceptually denotes that the = is modified to allow for a certain deviation. In other words, we have a modified function. This calls for an operator! Now consider

x (=±2) 1

where it is clear that = is modified by ± to allow a deviation of 2:

      ¯5 ¯1 1 3 4 5 (=±2) 1
 0 1 1 1 0 0

Applicability

Where could a range be allowed in an otherwise precise (save for ⎕CT) comparison? Well, everywhere where ⎕CT is an implicit argument of course! That is, the monadic primitive functions Ceiling (), Floor () and Unique () and the dyadic functions Equal (=), Excluding (~), Find (), Greater (>), Greater or Equal (), Index of (), Intersection (), Less (<), Less or Equal (), Match (), Membership (), Not Match (), Not Equal (), Residue (|) and Union (), as well as ⎕FMT's O-format.

Use cases

There are several real-world examples where the equivalent current-APL code would be much simpler using this operator. Here are a few examples:

Monadic uses of absolute deviation

Round up if much above lower integer:
      (⌈±0 0.2) 1.6 1.9 2 2.2 2.3
 2 2 2 2 3
Elements that far from each other:
       (∪±0 0.2) 1.6 1.9 2 2.2 2.3
 1.6 1.9 2.2

Dyadic uses of absolute deviation

Remove elements ≈ 2:
      1.6 1.9 2 2.2 2.3 (~±0 0.2) 2
 1.6 2.3
Index of first element ≈ 2:
      1.6 1.9 2 2.2 2.3 (⍳±0 0.2) 2 
 2
Close-enough match?
      1.6 1.9 2 2.2 2.3 (≡±0 0.2) 1.5 2 2 2 1.5
 1

Relative deviation

Within 5% of any element?
      1.7 2.4 (∊±0.05) 1.6 1.9 2 2.2 2.3
 0 1
With a set of tiles that are 4 cm long, can the given walls be covered if we allow 5% fuzziness through varying the amount of grout?
      0 = 4 (|±0.05) 16 19 20 22 23
 1 0 1 0 1

Both relative and absolute deviation

Is the joystick input neutral or within 10% of 1000?
      heading (∊±1 0.1) 0 request
 1 0 1 0 1

  • As so much in regular mathematics, the notation x = 1 ± 2 is ambiguous. An identical notation is used for the roots of p = 2x² − 4x – 6, namely x = 1 ± 2, that is, both x = −1 and x = 3, but of course not any value in between them. See Wikipedia.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment