h$MHF      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~None,5679>?0 numhask-spaceAn  is something that can be subjected to an affine transformation in 2-dimensional space, where affine means a linear matrix operation or a translation (+). 3https://en.wikipedia.org/wiki/Affine_transformation numhask-space3linear transform + translate of a point-like number $(x, y) -> (ax + by + c, dx + ey + d)or \begin{pmatrix} a & b & c\\ d & e & f\\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} x\\ y\\ 1 \end{pmatrix}  numhask-spacePos suggests where points should be placed in forming a grid across a field space.  numhask-spaceinclude boundaries  numhask-spacedon't include boundaries  numhask-spaceinclude the lower boundary numhask-spaceinclude the upper boundary numhask-spaceuse the mid-point of the space numhask-space"a space that can be divided neatly unsafeSpace1 (grid OuterPos s g) == s getUnion (sconcat (Union <$> (gridSpace s g))) == s numhask-space-create equally-spaced elements across a space numhask-space)create equally-spaced spaces from a space numhask-space 7https://en.wikipedia.org/wiki/Intersection_(set_theory) numhask-space a convex hull numhask-spaceA  is a continuous set of numbers. Continuous here means that the set has an upper and lower bound, and an element that is between these two bounds is a member of the . a `union` b == b `union` a a `intersection` b == b `intersection` a (a `union` b) `intersection` c == (a `intersection` b) `union` (a `intersection` c) (a `intersection` b) `union` c == (a `union` b) `intersection` (a `union` c) norm (norm a) = norm a a |>| b == b |<| a a |.| singleton a numhask-space#the underlying element in the space numhask-spacelower boundary numhask-spaceupper boundary numhask-space!space containing a single element numhask-spacethe intersection of two spaces  numhask-spacethe union of two spaces! numhask-spaceNormalise a space so that ;lower a \/ upper a == lower a lower a /\ upper a == upper a" numhask-space+create a normalised space from two elements# numhask-space4create a space from two elements without normalising$ numhask-spaceis an element in the space% numhask-space'is one space completely above the other& numhask-space'is one space completely below the other' numhask-space$is a space contained within another? 5(a `union` b) `contains` a (a `union` b) `contains` b( numhask-spaceare two spaces disjoint?) numhask-space&is an element contained within a space* numhask-spacedistance between boundaries+ numhask-space,create a space centered on a plus or minus b, numhask-space!supply a random element within a randomS (one :: Range Double) g(0.43085240252163404,StdGen {unStdGen = SMGen 4530528345362647137 13679457532755275413})- numhask-spaceStatefulGen version of randomSimport Control.Monad/runStateGen_ g (randomSM (one :: Range Double))0.43085240252163404. numhask-space#list of n random elements within a let g = mkStdGen 42(fst (randomSs 3 (one :: Range Double) g)>[0.43085240252163404,-6.472345419562497e-2,0.3854692674681801]/fst (randomSs 3 (Rect 0 10 0 10 :: Rect Int) g)[Point 0 7,Point 0 2,Point 1 7]/ numhask-spacemiddle element of the space0 numhask-spaceinterpolate a space -interpolate s x == project s (zero ... one) x1 numhask-spaceproject an element from one space to another, preserving relative position. project o n (lower o) = lower n project o n (upper o) = upper n project o n (mid o) = mid n project a a x = x2 numhask-space0the containing space of a non-empty Traversable.partial function. %all $ unsafeSpace1 a `contains` <$> a3 numhask-space(Maybe containing space of a traversable.4 numhask-spacelift a monotone function (increasing or decreasing) over a given space5 numhask-space a small space6 numhask-space widen a space7 numhask-spacewiden by a small amount8 numhask-space&Scale a Space. (scalar multiplication)9 numhask-spaceMove a Space. (scalar addition): numhask-space*Calculate the inverse of a transformation.; numhask-spaceApply a  to an < numhask-space Rotate an  (counter-clockwise)=  #!"$%&'()*+,-./0123456789:;<"3#3$7%7&7+6;3None ,8>?= numhask-spaceA continuous range over type alet a = Range (-1) 1a Range -1 1a + a Range -2 2a * aRange -2.0 2.0(+1) <$> (Range 1 2) Range 2 3Ranges are very useful in shifting a bunch of numbers from one Range to another. eg project 0.5 from the range 0 to 1 to the range 1 to 4#project (Range 0 1) (Range 1 4) 0.52.5Create an equally spaced grid including outer bounds over a Range grid OuterPos (Range 0.0 10.0) 5[0.0,2.0,4.0,6.0,8.0,10.0]+divide up a Range into equal-sized sectionsgridSpace (Range 0.0 1.0) 4=[Range 0.0 0.25,Range 0.25 0.5,Range 0.5 0.75,Range 0.75 1.0]? numhask-space'a grid for five-digits per limb species2gridSensible OuterPos False (Range (-12.0) 23.0) 6.[-15.0,-10.0,-5.0,0.0,5.0,10.0,15.0,20.0,25.0]E numhask-space!Monoid based on convex hull union=>?=>?None,8?) X numhask-space(whether to include lower and upper times[ numhask-spacea step in timeb numhask-spaceparse text as per iso8601 parseUTCTime (pack "2017-12-05")Just 2017-12-05 00:00:00 UTCc numhask-space convenience conversion to Doubled numhask-space"convenience conversion from Doublee numhask-space Convert from  to seconds (as a Double)fromDiffTime $ toDiffTime 11.0f numhask-space&Convert from seconds (as a Double) to  >>> toDiffTime 1 1sg numhask-spaceadd a TimeGrain to a UTCTimeaddGrain (Years 1) 5 (UTCTime (fromGregorian 2015 2 28) (toDiffTime 0))2020-02-29 00:00:00 UTCaddGrain (Months 1) 1 (UTCTime (fromGregorian 2015 2 28) (toDiffTime 0))2015-03-31 00:00:00 UTCaddGrain (Hours 6) 5 (UTCTime (fromGregorian 2015 2 28) (toDiffTime 0))2015-03-01 06:00:00 UTCaddGrain (Seconds 0.001) (60*1000+1) (UTCTime (fromGregorian 2015 2 28) (toDiffTime 0))2015-02-28 00:01:00.001 UTCh numhask-space0compute the floor UTCTime based on the timegrainfloorGrain (Years 5) (UTCTime (fromGregorian 1999 1 1) (toDiffTime 0))1995-12-31 00:00:00 UTCfloorGrain (Months 3) (UTCTime (fromGregorian 2016 12 30) (toDiffTime 0))2016-09-30 00:00:00 UTCfloorGrain (Days 5) (UTCTime (fromGregorian 2016 12 30) (toDiffTime 1))2016-12-30 00:00:00 UTCfloorGrain (Minutes 15) (UTCTime (fromGregorian 2016 12 30) (toDiffTime $ 15*60+1))2016-12-30 00:15:00 UTCfloorGrain (Seconds 0.1) (UTCTime (fromGregorian 2016 12 30) ((toDiffTime 0.12)))2016-12-30 00:00:00.1 UTCi numhask-space2compute the ceiling UTCTime based on the timegrainceilingGrain (Years 5) (UTCTime (fromGregorian 1999 1 1) (toDiffTime 0))2000-12-31 00:00:00 UTCceilingGrain (Months 3) (UTCTime (fromGregorian 2016 12 30) (toDiffTime 0))2016-12-31 00:00:00 UTCceilingGrain (Days 5) (UTCTime (fromGregorian 2016 12 30) (toDiffTime 1))2016-12-31 00:00:00 UTCceilingGrain (Minutes 15) (UTCTime (fromGregorian 2016 12 30) (toDiffTime $ 15*60+1))2016-12-30 00:30:00 UTCceilingGrain (Seconds 0.1) (UTCTime (fromGregorian 2016 12 30) (toDiffTime 0.12))2016-12-30 00:00:00.2 UTCj numhask-spaceDates used for time series analysis or attached to charts are often discontinuous, but we want to smooth that reality over and show a continuous range on the axis.The assumption with getSensibleTimeGrid is that there is a list of discountinuous UTCTimes rather than a continuous range. Output is a list of index points for the original [UTCTime] and label tuples, and a list of unused list elements.placedTimeLabelDiscontinuous PosIncludeBoundaries (Just (pack "%d %b")) 2 [UTCTime (fromGregorian 2017 12 6) (toDiffTime 0), UTCTime (fromGregorian 2017 12 29) (toDiffTime 0), UTCTime (fromGregorian 2018 1 31) (toDiffTime 0), UTCTime (fromGregorian 2018 3 3) (toDiffTime 0)]:([(0,"06 Dec"),(1,"31 Dec"),(2,"28 Feb"),(3,"03 Mar")],[])k numhask-spaceA sensible time grid between two dates, projected onto (0,1) with no attempt to get finnicky.placedTimeLabelContinuous PosIncludeBoundaries (Just (pack "%d %b")) 2 (Range (UTCTime (fromGregorian 2017 12 6) (toDiffTime 0)) (UTCTime (fromGregorian 2017 12 29) (toDiffTime 0)))[(0.0,"06 Dec"),(0.4347826086956521,"16 Dec"),(0.8695652173913042,"26 Dec"),(0.9999999999999999,"29 Dec")]l numhask-space1compute a sensible TimeGrain and list of UTCTimessensibleTimeGrid InnerPos 2 (Range (UTCTime (fromGregorian 2016 12 31) (toDiffTime 0)) (UTCTime (fromGregorian 2017 12 31) (toDiffTime 0)))(Months 6,[2016-12-31 00:00:00 UTC,2017-06-30 00:00:00 UTC,2017-12-31 00:00:00 UTC])sensibleTimeGrid InnerPos 2 (Range (UTCTime (fromGregorian 2017 1 1) (toDiffTime 0)) (UTCTime (fromGregorian 2017 12 30) (toDiffTime 0)))$(Months 6,[2017-06-30 00:00:00 UTC])sensibleTimeGrid UpperPos 2 (Range (UTCTime (fromGregorian 2017 1 1) (toDiffTime 0)) (UTCTime (fromGregorian 2017 12 30) (toDiffTime 0)))<(Months 6,[2017-06-30 00:00:00 UTC,2017-12-31 00:00:00 UTC])sensibleTimeGrid LowerPos 2 (Range (UTCTime (fromGregorian 2017 1 1) (toDiffTime 0)) (UTCTime (fromGregorian 2017 12 30) (toDiffTime 0)))<(Months 6,[2016-12-31 00:00:00 UTC,2017-06-30 00:00:00 UTC])XYZ[\]^_`abcdefghijklb[\]^_`ahiglXYZjkcdefNone,5678>?1p numhask-spaceA line is a composed of 2 tst numhask-spaceA 2-dimensional Point of a'sIn contrast with a tuple, a Point is functorial over both arguments.let p = Point 1 1p + p Point 2 2 (2*) <$> p Point 2 2A major reason for this bespoke treatment (compared to just using linear, say) is that Points do not have maximums and minimums but they do form a lattice, and this is useful for folding sets of points to find out the (rectangular) Space they occupy.Point 0 1 /\ Point 1 0 Point 0 0Point 0 1 \/ Point 1 0 Point 1 1This is used extensively in  -https://hackage.haskell.org/package/chart-svg chart-svg% to ergonomically obtain chart areas. 2unsafeSpace1 [Point 1 0, Point 0 1] :: Rect DoubleRect 0.0 1.0 0.0 1.0x numhask-spacemove an  by a ty numhask-space scale an  by a tz numhask-spaceSkew transform x-axis skew skew (Point x 0){ numhask-space*rotate a point by x relative to the originrotateP (pi/2) (Point 1 0)Point 6.123233995736766e-17 1.0| numhask-space7Create Points for a formulae y = f(x) across an x rangegridP (^2) (Range 0 4) 4[Point 0.0 0.0,Point 1.0 1.0,Point 2.0 4.0,Point 3.0 9.0,Point 4.0 16.0]} numhask-space dot product~ numhask-spacedot product operator numhask-space cross product numhask-spacereflect on x-axis numhask-space6Return the parameters (a, b, c) for the line equation a*x + b*y + c = 0. numhask-spaceReturn the signed distance from a point to the line. If the distance is negative, the point lies to the right of the line numhask-space8Return the point on the line closest to the given point. numhask-spaceCalculate the intersection of two lines. If the determinant is less than tolerance (parallel or coincident lines), return Nothing. numhask-spaceangle formed by a vector from the origin to a Point and the x-axis (Point 1 0). Note that an angle between two points p1 & p2 is thus angle p2 - angle p1pqrstuvwxyz{|}~tuvw{|}~pqrsxyz~4None,5678>??W numhask-spacea rectangular space often representing a finite 2-dimensional or XY plane.one :: Rect DoubleRect -0.5 0.5 -0.5 0.5zero :: Rect DoubleRect 0.0 0.0 0.0 0.0one + one :: Rect DoubleRect -1.0 1.0 -1.0 1.0"let a = Rect (-1.0) 1.0 (-2.0) 4.0aRect -1.0 1.0 -2.0 4.0a * oneRect -1.0 1.0 -2.0 4.0let (Ranges x y) = axRange -1.0 1.0yRange -2.0 4.0fmap (+1) (Rect 1 2 3 4) Rect 2 3 4 5+as a Space instance with Points as Elementsproject (Rect 0.0 1.0 (-1.0) 0.0) (Rect 1.0 4.0 10.0 0.0) (Point 0.5 1.0)Point 2.5 -10.0;gridSpace (Rect 0.0 10.0 0.0 1.0) (Point (2::Int) (2::Int))[Rect 0.0 5.0 0.0 0.5,Rect 0.0 5.0 0.5 1.0,Rect 5.0 10.0 0.0 0.5,Rect 5.0 10.0 0.5 1.0]=grid MidPos (Rect 0.0 10.0 0.0 1.0) (Point (2::Int) (2::Int))=[Point 2.5 0.25,Point 2.5 0.75,Point 7.5 0.25,Point 7.5 0.75] numhask-spacepattern of Ranges xrange yrange numhask-space+pattern of Rect lowerx upperx lowery uppery numhask-spacecreate a list of points representing the lower left and upper right corners of a rectangle. corners one[Point -0.5 -0.5,Point 0.5 0.5] numhask-space the 4 corners corners4 one=[Point -0.5 -0.5,Point -0.5 0.5,Point 0.5 -0.5,Point 0.5 0.5] numhask-space5project a Rect from an old Space (Rect) to a new one.The Space instance of Rect uses Points as Elements, but a Rect can also be a Space over Rects.projectRect (Rect 0 1 (-1) 0) (Rect 0 4 0 8) (Rect 0.25 0.75 (-0.75) (-0.25))Rect 1.0 3.0 2.0 6.0 numhask-spaceconvex hull union of Rect'sfoldRect [Rect 0 1 0 1, one]Just Rect -0.5 1.0 -0.5 1.0 numhask-space x * y) (Rect 0 4 0 4) (Point 2 2)[(Rect 0.0 2.0 0.0 2.0,1.0),(Rect 0.0 2.0 2.0 4.0,3.0),(Rect 2.0 4.0 0.0 2.0,3.0),(Rect 2.0 4.0 2.0 4.0,9.0)] numhask-space8convert a ratio (eg x:1) to a Rect with a height of one.aspect 2Rect -1.0 1.0 -0.5 0.5 numhask-spaceconvert a Rect to a ratio:set -XNegativeLiteralsratio (Rect -1 1 -0.5 0.5)2.0 numhask-spaceproject a Rect from one Rect to another, preserving relative position, with guards for singleton Rects.0projectOnR one (Rect 0 1 0 1) (Rect 0 0.5 0 0.5)Rect -0.5 0.0 -0.5 0.0 numhask-spaceproject a Point from one Rect to another, preserving relative position, with guards for singleton Rects."projectOnP one (Rect 0 1 0 1) zeroPoint -0.5 -0.5 numhask-spaceNumeric algebra based on interval arithmetioc for addition and unitRect and projection for multiplication >>> one + one :: Rect Double Rect -1.0 1.0 -1.0 1.0None,/F  numhask-spaceWhether or not to ignore unders and overs. If overs and unders are dealt with, IncludeOvers supplies an assumed width for the outer buckets. numhask-spaceThis Histogram is a list of contiguous boundaries (a boundary being the lower edge of one bucket and the upper edge of another), and a value (usually a count) for each bucket, represented here as a mapOvers and Unders are contained in key = 0 and key = length cuts Intervals are defined as (l,u] numhask-space"A histogram with no cuts nor data. numhask-space)Fill a Histogram using pre-specified cutsfill [0,50,100] [0..99]Histogram {cuts = [0.0,50.0,100.0], values = fromList [(1,50.0),(2,50.0)]} numhask-space7find the index of the bucket the value is contained in. numhask-spaceMake a histogram using n equally spaced cuts over the entire range of the dataregular 4 [0..100]Histogram {cuts = [0.0,25.0,50.0,75.0,100.0], values = fromList [(1,25.0),(2,25.0),(3,25.0),(4,25.0),(5,1.0)]} numhask-spaceTransform a Histogram to Rects*makeRects IgnoreOvers (regular 4 [0..100])[Rect 0.0 25.0 0.0 0.25,Rect 25.0 50.0 0.0 0.25,Rect 50.0 75.0 0.0 0.25,Rect 75.0 100.0 0.0 0.25] numhask-spaceapprox regular n-quantilesregularQuantiles 4 [0..100][0.0,24.75,50.0,75.25,100.0] numhask-space#one-pass approximate quantiles fold numhask-spacenormalize a histogram "\h -> sum (values $ freq h) == onefreq $ fill [0,50,100] [0..99]Histogram {cuts = [0.0,50.0,100.0], values = fromList [(1,0.5),(2,0.5)]} numhask-spaceaverageaverage [0..1000]500.0 numhask-space#Regularly spaced (approx) quantilesquantiles 5 [1..1000]0[1.0,200.5,400.5,600.5000000000001,800.5,1000.0] numhask-spacesingle (approx) quantilequantile 0.1 [1..1000]100.5None,GM   &%$"!# '()*+,-./0123456789:;<=>?XYZ[a`_^\]bcdefghijklpqrstuvwxyz{|}~= #!"$%&/01 32,-.)'(*+456789 :;<       !"#$%&'()*+,-./0123456789:;<=>?@ABBCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrsttuvwwxyz{|}~,numhask-space-0.9.0.0-6mqiJFN8EiyFz54Hiywrkl NumHask.SpaceNumHask.Space.RangeNumHask.Space.TimeNumHask.Space.PointNumHask.Space.RectNumHask.Space.HistogramNumHask.Space.TypesAffinity transform TransformtatbtctdtetfPosOuterPosInnerPosLowerPosUpperPosMidPos FieldSpaceGridgrid gridSpace IntersectiongetIntersectionUniongetUnionSpaceElementlowerupper singleton intersectionunion normalise...>.<|.||>||<|containsdisjointmemberOfwidth+/-randomSrandomSMrandomSsmid interpolateproject unsafeSpace1space1monotoneepswidenwidenEpsscalemoveinverseTransform|.rotateRange gridSensible $fSignedRange$fDivisiveRange$fMultiplicativeRange$fSubtractiveRange$fAdditiveRange$fSemigroupRange$fFieldSpaceRange $fSpaceRange$fMeetSemiLatticeRange$fJoinSemiLatticeRange$fRepresentableRange$fDistributiveRange$fTraversable1Range$fTraversableRange$fFoldable1Range$fFoldableRange$fApplicativeRange $fApplyRange$fFunctorRange $fShow1Range $fEq1Range $fShowRange $fEqRange$fGenericRangePosDiscontinuous PosInnerOnlyPosIncludeBoundaries TimeGrainYearsMonthsDaysHoursMinutesSeconds parseUTCTimefromNominalDiffTimetoNominalDiffTime fromDiffTime toDiffTimeaddGrain floorGrain ceilingGrainplacedTimeLabelDiscontinuousplacedTimeLabelContinuoussensibleTimeGrid$fShowTimeGrain $fEqTimeGrain$fGenericTimeGrainLine lineStartlineEndPoint_x_y translatescaleTskewrotatePgridPdotP<.>crossPflipY lineSolve lineDistance closestPoint lineIntersect$fAffinityPointa$fUniformRangePoint$fDirectionPointa $fNormPointa$fMeetSemiLatticePoint$fJoinSemiLatticePoint$fRepresentablePoint$fDivisiveActionPointa$fMultiplicativeActionPointa$fSubtractiveActionPointa$fAdditiveActionPointa$fDistributivePoint$fDivisivePoint $fSignedPoint $fFieldPoint$fDistributivePoint0$fMultiplicativePoint$fSubtractivePoint$fAdditivePoint$fBoundedPoint $fMonoidPoint$fSemigroupPoint$fTraversablePoint$fFoldablePoint $fMonadPoint$fApplicativePoint $fShow1Point $fEq1Point$fFunctorPoint $fShowPoint$fAffinityLinea $fShowLine$fEqLine $fFunctorLine$fFoldableLine$fTraversableLine $fEqPoint$fGenericPointRectRect'Rangescornerscorners4 projectRectfoldRectfoldRectUnsafeaddPoint rotationBoundgridRgridFaspectratio projectOnR projectOnP $fSignedRect$fDivisiveRect$fMultiplicativeRect$fSubtractiveRect$fAdditiveRect$fFieldSpaceRect $fSpaceRect$fSemigroupRect$fRepresentableRect$fDistributiveRect $fShowRect$fEqRect $fFunctorRect$fApplicativeRect$fFoldableRect$fTraversableRect $fGenericRect DealOvers IgnoreOvers IncludeOvers HistogramcutsvaluesemptyHistogramfillcutIregular makeRectsregularQuantiles quantileFoldfreqaverage quantilesquantile$fShowHistogram $fEqHistogram time-1.9.3!Data.Time.Clock.Internal.DiffTimeDiffTime