--------------------------------------------------------------------------------
-- |
-- Module      :  Algorithms.Geometry.RedBlueSeparator.RIC
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--
-- Given a set of red points and a set of blue points in \(\mathbb{R}^2\) finds
-- a separating line in \(O(n)\) expected time, where \(n\) is the total number
-- of points.
--
--------------------------------------------------------------------------------
module Algorithms.Geometry.RedBlueSeparator.RIC where


import           Algorithms.Geometry.LinearProgramming.LP2DRIC
import           Algorithms.Geometry.LinearProgramming.Types
import           Control.Applicative ((<|>))
import           Control.Lens hiding (below)
import           Control.Monad.Random.Class
import           Data.Ext
import qualified Data.Foldable as F
import           Data.Geometry.HalfSpace
import           Data.Geometry.Line
import           Data.Geometry.Point
import           Data.Geometry.Vector
import           Data.Ord (comparing)
import           Data.Semigroup.Foldable
import           Data.Util

--------------------------------------------------------------------------------

-- -- | Given a set of red points and a set of blue points in \(\mathbb{R}^2\)
-- -- finds a separating line (if it exists). The result is strict in the
-- -- sense that there will not be any points on the line.
-- --
-- --
-- -- running time: \(O(n)\) expected time, where \(n\) is the total number
-- -- of points.
-- strictSeparatingLine = undefined

-- | Given a set of red points and a set of blue points in \(\mathbb{R}^2\)
-- finds a separating line (if it exists). The result is non-strict in the
-- sense that there may be points *on* the line.
--
--
-- running time: \(O(n)\) expected time, where \(n\) is the total number
-- of points.
separatingLine :: (MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r)
               => f (Point 2 r :+ redData)
               -> g (Point 2 r :+ blueData)
               -> m (Maybe (Line 2 r))
separatingLine :: f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r))
separatingLine f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = do Maybe (Line 2 r)
l <- f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r))
forall (m :: * -> *) (f :: * -> *) (g :: * -> *) r redData
       blueData.
(MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r) =>
f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r))
separatingLine' f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues
                               Maybe (Line 2 r)
m <- g (Point 2 r :+ blueData)
-> f (Point 2 r :+ redData) -> m (Maybe (Line 2 r))
forall (m :: * -> *) (f :: * -> *) (g :: * -> *) r redData
       blueData.
(MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r) =>
f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r))
separatingLine' g (Point 2 r :+ blueData)
blues f (Point 2 r :+ redData)
reds
                               Maybe (Line 2 r) -> m (Maybe (Line 2 r))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (Line 2 r) -> m (Maybe (Line 2 r)))
-> Maybe (Line 2 r) -> m (Maybe (Line 2 r))
forall a b. (a -> b) -> a -> b
$ Maybe (Line 2 r)
l Maybe (Line 2 r) -> Maybe (Line 2 r) -> Maybe (Line 2 r)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe (Line 2 r)
m

-- | Given a set of red points and a set of blue points in \(\mathbb{R}^2\)
-- finds a separating line (if it exists) that has all red points *right* (or
-- on) the line, and all blue points left (or on) the line.
--
-- running time: \(O(n)\) expected time, where \(n\) is the total number
-- of points.
separatingLine' :: (MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r)
                => f (Point 2 r :+ redData)
                -> g (Point 2 r :+ blueData)
                -> m (Maybe (Line 2 r))
separatingLine' :: f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r))
separatingLine' f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = case f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> SP
     (Maybe (Line 2 r)) (Point 2 r :+ redData, Point 2 r :+ blueData)
forall (f :: * -> *) (g :: * -> *) r redData blueData.
(Foldable1 f, Foldable1 g, Num r, Ord r) =>
f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> SP
     (Maybe (Line 2 r)) (Point 2 r :+ redData, Point 2 r :+ blueData)
verticalSeparatingLine f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues of
    SP Maybe (Line 2 r)
Nothing (Point 2 r
r:+redData
_,Point 2 r
b :+ blueData
_) -> Point 2 r
-> Point 2 r
-> f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> m (Maybe (Line 2 r))
forall (m :: * -> *) (f :: * -> *) (g :: * -> *) r redData
       blueData.
(MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r) =>
Point 2 r
-> Point 2 r
-> f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> m (Maybe (Line 2 r))
separatingLine'' Point 2 r
r Point 2 r
b f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues
      -- observe that if r and b were vertically above each other then we would
      -- have found a separating line. So r and b are not vertically
      -- aligned. Hence we satisfy the precondition.
    SP ml :: Maybe (Line 2 r)
ml@(Just Line 2 r
_) (Point 2 r :+ redData, Point 2 r :+ blueData)
_         -> Maybe (Line 2 r) -> m (Maybe (Line 2 r))
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (Line 2 r)
ml  -- already found a line


-- | given a red and blue point that are *NOT* vertically alligned, and all red
-- and all blue points, try to find a non-vertical separating line.
--
-- running time: \(O(n)\) expected time, where \(n\) is the total number
-- of points.
separatingLine'' :: (MonadRandom m, Foldable1 f, Foldable1 g, Fractional r, Ord r)
                => Point 2 r -- ^ red point r
                -> Point 2 r -- ^ a blue point b
                -> f (Point 2 r :+ redData)
                -> g (Point 2 r :+ blueData)
                -> m (Maybe (Line 2 r))
separatingLine'' :: Point 2 r
-> Point 2 r
-> f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> m (Maybe (Line 2 r))
separatingLine'' Point 2 r
r Point 2 r
b f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = (Point 2 r -> Line 2 r) -> Maybe (Point 2 r) -> Maybe (Line 2 r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Point 2 r -> Line 2 r
forall r. Num r => Point 2 r -> Line 2 r
mkLine (Maybe (Point 2 r) -> Maybe (Line 2 r))
-> m (Maybe (Point 2 r)) -> m (Maybe (Line 2 r))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LinearProgram 2 r -> m (Maybe (Point 2 r))
forall (m :: * -> *) r.
(MonadRandom m, Ord r, Fractional r) =>
LinearProgram 2 r -> m (Maybe (Point 2 r))
solveBoundedLinearProgram LinearProgram 2 r
lp
  where
    lp :: LinearProgram 2 r
lp = Vector 2 r -> [HalfSpace 2 r] -> LinearProgram 2 r
forall (d :: Nat) r.
Vector d r -> [HalfSpace d r] -> LinearProgram d r
LinearProgram Vector 2 r
c ([Point 2 r -> HalfSpace 2 r
forall r. Num r => Point 2 r -> HalfPlane r
mkRed Point 2 r
r, Point 2 r -> HalfSpace 2 r
forall r. Num r => Point 2 r -> HalfPlane r
mkBlue Point 2 r
b] [HalfSpace 2 r] -> [HalfSpace 2 r] -> [HalfSpace 2 r]
forall a. Semigroup a => a -> a -> a
<> [HalfSpace 2 r]
hs)

    c :: Vector 2 r
c = case (Point 2 r
rPoint 2 r -> Getting r (Point 2 r) r -> r
forall s a. s -> Getting a s a -> a
^.Getting r (Point 2 r) r
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord) r -> r -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (Point 2 r
bPoint 2 r -> Getting r (Point 2 r) r -> r
forall s a. s -> Getting a s a -> a
^.Getting r (Point 2 r) r
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord) of
          Ordering
LT -> r -> r -> Vector 2 r
forall r. r -> r -> Vector 2 r
Vector2 (-r
1) r
0  -- minimize a
          Ordering
GT -> r -> r -> Vector 2 r
forall r. r -> r -> Vector 2 r
Vector2 r
1    r
0  -- maximize a
          Ordering
EQ -> [Char] -> Vector 2 r
forall a. HasCallStack => [Char] -> a
error [Char]
"separatingLine'': precondition failed. r and b vertically above each other"

    mkLine :: Point 2 r -> Line 2 r
mkLine (Point2 r
aa r
bb) = r -> r -> Line 2 r
forall r. Num r => r -> r -> Line 2 r
fromLinearFunction r
aa r
bb

    -- red points generate the constraint: ry <= a*rx + b <=> b >= (-rx)a + ry
    mkRed :: Point 2 r -> HalfPlane r
mkRed (Point2 r
rx r
ry)  = Line 2 r -> HalfPlane r
forall r. Num r => Line 2 r -> HalfPlane r
above (Line 2 r -> HalfPlane r) -> Line 2 r -> HalfPlane r
forall a b. (a -> b) -> a -> b
$ r -> r -> Line 2 r
forall r. Num r => r -> r -> Line 2 r
fromLinearFunction ((-r
1)r -> r -> r
forall a. Num a => a -> a -> a
*r
rx) r
ry
    -- blue points generate the constraint: by >= a*bx + b <=> b <= (-bx)a + by
    mkBlue :: Point 2 r -> HalfPlane r
mkBlue (Point2 r
bx r
by) = Line 2 r -> HalfPlane r
forall r. Num r => Line 2 r -> HalfPlane r
below (Line 2 r -> HalfPlane r) -> Line 2 r -> HalfPlane r
forall a b. (a -> b) -> a -> b
$ r -> r -> Line 2 r
forall r. Num r => r -> r -> Line 2 r
fromLinearFunction ((-r
1)r -> r -> r
forall a. Num a => a -> a -> a
*r
bx) r
by

    hs :: [HalfSpace 2 r]
hs = [Point 2 r -> HalfSpace 2 r
forall r. Num r => Point 2 r -> HalfPlane r
mkRed Point 2 r
rr | (Point 2 r
rr :+ redData
_) <- f (Point 2 r :+ redData) -> [Point 2 r :+ redData]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList f (Point 2 r :+ redData)
reds] [HalfSpace 2 r] -> [HalfSpace 2 r] -> [HalfSpace 2 r]
forall a. Semigroup a => a -> a -> a
<> [Point 2 r -> HalfSpace 2 r
forall r. Num r => Point 2 r -> HalfPlane r
mkBlue Point 2 r
bb | (Point 2 r
bb :+ blueData
_) <- g (Point 2 r :+ blueData) -> [Point 2 r :+ blueData]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList g (Point 2 r :+ blueData)
blues]


--------------------------------------------------------------------------------
-- * Vertical Separators

-- | Computes a strict vertical separating line, if one exists
strictVerticalSeparatingLine            :: (Foldable1 f, Foldable1 g, Fractional r, Ord r)
                                        => f (Point 2 r :+ redData)
                                        -> g (Point 2 r :+ blueData)
                                        -> Maybe (Line 2 r)
strictVerticalSeparatingLine :: f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData) -> Maybe (Line 2 r)
strictVerticalSeparatingLine f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = do let (Point 2 r :+ redData
r,Point 2 r :+ blueData
b) = f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
forall (f :: * -> *) (g :: * -> *) r redData blueData.
(Foldable1 f, Foldable1 g, Ord r) =>
f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
extremalPoints f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues
                                                 rx :: r
rx    = Point 2 r :+ redData
r(Point 2 r :+ redData) -> Getting r (Point 2 r :+ redData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ redData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord
                                                 bx :: r
bx    = Point 2 r :+ blueData
b(Point 2 r :+ blueData) -> Getting r (Point 2 r :+ blueData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ blueData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord
                                             if r
bx r -> r -> Bool
forall a. Ord a => a -> a -> Bool
< r
rx
                                               then Line 2 r -> Maybe (Line 2 r)
forall a. a -> Maybe a
Just (Line 2 r -> Maybe (Line 2 r))
-> (r -> Line 2 r) -> r -> Maybe (Line 2 r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> Line 2 r
forall r. Num r => r -> Line 2 r
verticalLine (r -> Maybe (Line 2 r)) -> r -> Maybe (Line 2 r)
forall a b. (a -> b) -> a -> b
$ (r
rx r -> r -> r
forall a. Num a => a -> a -> a
+ r
bx) r -> r -> r
forall a. Fractional a => a -> a -> a
/ r
2
                                               else Maybe (Line 2 r)
forall a. Maybe a
Nothing -- no vertical separator


-- | Test if there is a vertical separating line that has all red points to its
-- right (or on it) and all blue points to its left (or on it).  This function
-- also returns the two extremal points; in case a line is returned, the line
-- actually goes through the blue (second) point, if there is no line, this
-- pair provides evidence that there is no vertical separating line.
--
-- The line we return actually goes through one blue point.
verticalSeparatingLine            :: (Foldable1 f, Foldable1 g, Num r, Ord r)
                                  => f (Point 2 r :+ redData)
                                  -> g (Point 2 r :+ blueData)
                                  -> SP (Maybe (Line 2 r))
                                        (Point 2 r :+ redData, Point 2 r :+ blueData)
verticalSeparatingLine :: f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> SP
     (Maybe (Line 2 r)) (Point 2 r :+ redData, Point 2 r :+ blueData)
verticalSeparatingLine f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = Maybe (Line 2 r)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
-> SP
     (Maybe (Line 2 r)) (Point 2 r :+ redData, Point 2 r :+ blueData)
forall a b. a -> b -> SP a b
SP Maybe (Line 2 r)
ml (Point 2 r :+ redData, Point 2 r :+ blueData)
es
  where
    es :: (Point 2 r :+ redData, Point 2 r :+ blueData)
es@(Point 2 r :+ redData
r,Point 2 r :+ blueData
b) = f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
forall (f :: * -> *) (g :: * -> *) r redData blueData.
(Foldable1 f, Foldable1 g, Ord r) =>
f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
extremalPoints f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues
    ml :: Maybe (Line 2 r)
ml = if Point 2 r :+ blueData
b(Point 2 r :+ blueData) -> Getting r (Point 2 r :+ blueData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ blueData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord r -> r -> Bool
forall a. Ord a => a -> a -> Bool
<= Point 2 r :+ redData
r(Point 2 r :+ redData) -> Getting r (Point 2 r :+ redData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ redData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord then Line 2 r -> Maybe (Line 2 r)
forall a. a -> Maybe a
Just (Line 2 r -> Maybe (Line 2 r))
-> (r -> Line 2 r) -> r -> Maybe (Line 2 r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> Line 2 r
forall r. Num r => r -> Line 2 r
verticalLine (r -> Maybe (Line 2 r)) -> r -> Maybe (Line 2 r)
forall a b. (a -> b) -> a -> b
$ (Point 2 r :+ blueData
b(Point 2 r :+ blueData) -> Getting r (Point 2 r :+ blueData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ blueData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord)
                                             else Maybe (Line 2 r)
forall a. Maybe a
Nothing

-- | Get the the leftmost red point and the rightmost blue point.
extremalPoints            :: (Foldable1 f, Foldable1 g, Ord r)
                          => f (Point 2 r :+ redData)
                          -> g (Point 2 r :+ blueData)
                          -> (Point 2 r :+ redData, Point 2 r :+ blueData)
extremalPoints :: f (Point 2 r :+ redData)
-> g (Point 2 r :+ blueData)
-> (Point 2 r :+ redData, Point 2 r :+ blueData)
extremalPoints f (Point 2 r :+ redData)
reds g (Point 2 r :+ blueData)
blues = (((Point 2 r :+ redData) -> (Point 2 r :+ redData) -> Ordering)
-> f (Point 2 r :+ redData) -> Point 2 r :+ redData
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
F.minimumBy (((Point 2 r :+ redData) -> r)
-> (Point 2 r :+ redData) -> (Point 2 r :+ redData) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing ((Point 2 r :+ redData) -> Getting r (Point 2 r :+ redData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ redData) -> Const r (Point 2 r :+ redData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ redData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord)) f (Point 2 r :+ redData)
reds
                            ,((Point 2 r :+ blueData) -> (Point 2 r :+ blueData) -> Ordering)
-> g (Point 2 r :+ blueData) -> Point 2 r :+ blueData
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
F.maximumBy (((Point 2 r :+ blueData) -> r)
-> (Point 2 r :+ blueData) -> (Point 2 r :+ blueData) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing ((Point 2 r :+ blueData) -> Getting r (Point 2 r :+ blueData) r -> r
forall s a. s -> Getting a s a -> a
^.(Point 2 r -> Const r (Point 2 r))
-> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Point 2 r -> Const r (Point 2 r))
 -> (Point 2 r :+ blueData) -> Const r (Point 2 r :+ blueData))
-> ((r -> Const r r) -> Point 2 r -> Const r (Point 2 r))
-> Getting r (Point 2 r :+ blueData) r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(r -> Const r r) -> Point 2 r -> Const r (Point 2 r)
forall (d :: Nat) (point :: Nat -> * -> *) r.
(1 <= d, Arity d, AsAPoint point) =>
Lens' (point d r) r
xCoord)) g (Point 2 r :+ blueData)
blues)

--------------------------------------------------------------------------------