txt: ## dist_zef-librasteve-Math-Interval.md
  [![](https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0)
  
  ## Math::Interval
  
  * viz. <https://en.wikipedia.org/wiki/Interval_arithmetic>
  * viz. <https://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node45.html>
  
  ### A elementary implementation of Interval Arithmetic using raku Ranges
  
  Check out the Wikipedia page first - sub and div may confound your expectations:
  
  ## Synopsis
  
  ```
  #!/usr/bin/env raku
  use lib '../lib';
  
  use Data::Dump::Tree;
  use Math::Interval;
  
  # Range-Range Operations use interval math
  say (1..2) + (2..4);        #3..6
  say (2..4) - (1..2);        #0..3  (yes - this is weird!)
  say (2..4) * (1..2);        #2..8
  say (2..4) / (1..2);        #1.0..4.0
  # strings work too! (must be numbers)
  say (1..2) + ('1'..'5');    #2..7
  # an Interval is returned
  say ((1..2) + (2..4)) ~~ Interval;  #True
  
  #| Interval is a child of class Range where endpoints are always Numeric
  #| No cats ears, not Positional, not Iterable, no .elems
  my Interval $i1 .= new(range => 2.5^..^8.5);    #3.5..7.5
  my Interval $i2 .= new(2..^8);                  #2e0..7e0
  my Interval $i3 .= new(1,2);                    #1..2
  my Interval $i4 .= new(4.5,6.5);                #4.5..6.5
  
  # '~~' checks if y contains x
  say   2 ~~ $i2;     #True
  say $i4 ~~ $i1;     #True
  say $i1 ~~ $i4;     #False
  
  # cmp checks Order
  say $i1 cmp $i1;    #Same
  say $i1 cmp $i3;    #More
  say $i3 cmp $i1;    #Less
  say $i1 cmp $i2;    #Nil   overlaps are not ordered
  say $i2 cmp $i1;    #Nil            ""
  
  # intersection ∩ [(&)] and union ∪ [(|)] 
  say $i3  ∩  $i4;    #∅ the null Set()
  say $i4  ∪  $i3;    #union returns a disjoint multi-interval unless args intersect
  
  # gotchas
  #say +$i1;          #fails - Interval has no .elems
  #say $i1.Set;       #fails - raku Sets must contain discrete items
  say $i1.Range.Set;  #coerce to Range to discretize an Interval
  
  ## the -Ofun bit
  
  # a divisor that spans 0 produces a disjoint multi-interval
  my $j1 = (2..4)/(-2..4);
  ddt $j1;            #any(-Inf..-1.0, 0.5..Inf).Junction
  say 3 ~~ $j1;       #True
  
  # Junction[Interval] can still be used
  my $j2 = $j1 + 2;
  ddt $j2;            #any(-Inf..1.0, 2.5..Inf).Junction
  say 5 ~~ $j2;       #True
  
  # but this can only go so far...
  my $j3 = $j1 * (-2..4);
  ddt $j3;            #any(-Inf..Inf, -Inf..Inf).Junction
  say 3 ~~ $j3;       #True (but meaningless!)
  
  ```
  
  ## Explanation
  
  We split the use cases of the built-in Range type as follows:
  
  ### class Range
  
  * Use case
    * to generate lists of consecutive numbers or strings
    * to act as a matcher to check if a Numeric or Stringy or Range is within a certain Range
  * endpoints with/out cats ears (±1)
  * does Positional, does Iterable
  * arithmetic +-\*/ operators with scalars are distributed to endpoints like Junction with 2 elems, then each endpoint coerced to .Int
  * prefix '+' special cased to .elems
  * use `~~` to check containment
    * `say 3 ~~ 1..12;` #True x1 <= a <= x2
    * `say 2..3 ~~ 1..12;` #True x1 >= y1 && x2 <= y2
    * `say 1..12 ~~ 2..3;` #False (y must contain x)
  * cmp works for Range op Range (for Real op Range .elems is used)
    * `(0..2) cmp (0..12)` #Less x1 < x2 || x1 == x2 && y1 < y2
    * `(0..2) cmp (0..2)` #Same x1 == x2 && y1 == y2
    * `(1..2) cmp (0..12)` #More x1 > x2 || x1 == x2 && y1 > y2
  * Set operations work for Any op Range and Range op Range by auto coercing both args via `.Set`
  
  ### class Interval
  
  * Use case
    * to act as a matcher to check if a Numeric or Interval is within a certain range
  * endpoints will ingest cats ears, x1 <= x2
  * not Iterable nor Positional
  * arithmetic +-\*/ operators with scalars are distributed to endpoints like Junction with 2 elems
  * Rangy op Rangy --> Interval arithmetic +-\*/ operators implemented
  * Rangy \*\* N --> Interval operator implemented
  * prefix '+' will fail (Interval has no .elems)
  * use `~~` to check containment
    * `say 3 ~~ 1..12;` #True x1 <= a <= x2
    * `say 2..3 ~~ 1..12;` #True x1 >= y1 && x2 <= y2
    * `say 1..12 ~~ 2..3;` #False (y must contain x)
  * cmp works for Interval op Interval
    * UNLIKE Range, overlapping intervals are not ordered and yet not equal
    * `(1..2) cmp (3..4)` #Less x2 < y1
    * `(1..2) cmp (2..4)` #Nil x2 !< y1 !!
    * `(0..2) cmp (0..2)` #Same x1 == x2 && y1 == y2
    * `(0..3) cmp (0..2)` #Nil x1 !> y2 !!
    * `(3..4) cmp (1..2)` #More x1 > y2
  
  Set operations
  `#say $i1.Set;` #fails - in general Sets contain discrete items and Intervals are continuous
  `say $i1.Range.Set;` #coerce to Range first to use all Set operators (which discretizes the Interval)
  
  However, the following two Set operations are implemented for Intervals:
  
  intersection (&) ∩
  `∅` if x1 > y2 || y1 > x2
  `max(x1,y1)..min(x2,y2)`
  
  union (|) ∪ (of two intersecting intervals)
  `min(x1,y1)..max(x2,y2)`
  
  other
  `(3..4).abs` #4 (always x2)
  `(3..4).width` #1 (x2-x1)
  
  which leads to these design points:
  
  * `class Interval is Range {...}`
  
    * so can be used wherever a Range is used
    * noting lack of Iterator or Positional support
  * `Interval: new $range`
  
    * rejects non-Real endpoints (eg. Str)
    * adjusts endpoints (±1) to strip cats ears
  * `.Range` coerces to Range
  * `subset Rangy of Any where * ~~ Range|Interval;`
  * No provision is (yet) made for Rounded Interval Arithmetic
  * No provision is (yet) made for complex intervals
  * Only a handful of all possible Interval operations (eg. log, exp, trig)
  * No use of standard libs such as [MPRIA](https://www.gnu.org/software/mpria/) or [MPFI](https://metacpan.org/pod/Math::MPFI)
  
  *Please feel free to submit any of these as a PR (see TODOs below)*
  
  ## TODOs
  
  ### Additional arithmetic operations
  
  * power (even / odd)
  * log / exp
  * trig
  * Newton
  
  ### Copyright
  
  copyright(c) 2023 Henley Cloud Consulting Ltd.
  