packages feed

hgeometry-0.7.0.0: test/Algorithms/Geometry/WellSeparatedPairDecomposition/WSPDSpec.hs

module Algorithms.Geometry.WellSeparatedPairDecomposition.WSPDSpec where

import           Algorithms.Geometry.Diameter
import           Algorithms.Geometry.WellSeparatedPairDecomposition.Types
import           Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD
import           Control.Lens
import           Data.Ext
import qualified Data.Foldable as F
import           Data.Geometry
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Seq2 as S2
import qualified Data.Set as Set
import qualified Data.Vector as V
import           Test.Hspec
import           Util
import           GHC.TypeLits

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

spec :: Spec
spec = do
  reIndexTest
  distributePointsTest

reIndexTest :: Spec
reIndexTest = describe "ReIndex tests" $ do
    it "simple input reordering " $ do
      reIndexPoints input `shouldBe` output
  where
    input = Vector2 (ptSeq [ origin :+ 1, point2 1 1 :+ 100, point2 5 5 :+ 101 ])
                    (ptSeq [ point2 1 1 :+ 100, point2 5 5 :+ 101, origin :+ 1 ])
    output = Vector2 (ptSeq [ origin :+ 0, point2 1 1 :+ 1, point2 5 5 :+ 2 ])
                     (ptSeq [ point2 1 1 :+ 1, point2 5 5 :+ 2, origin :+ 0 ])






distributePointsTest :: Spec
distributePointsTest = describe "DistributePoints tests" $ do
    it "distributePoints' on a single list " $ do
      distributePoints' 3 levels input `shouldBe` output
    it "distributePoints on multiple lists" $ do
      distributePoints 3 levels (Vector2 input input) `shouldBe` output'

  where
    levels = V.fromList [Just $ Level 0 (Just 2),Just $ Level 1 (Just 1), Nothing]
    input  = ptSeq [ origin :+ 0, point2 1 1 :+ 1, point2 2 2 :+ 2]
    output = V.fromList [ ptSeq [origin :+ 0]
                        , ptSeq [point2 1 1 :+ 1]
                        , ptSeq [point2 2 2 :+ 2]
                        ]
    output' = fmap (\pts -> Vector2 pts pts) output

    --     input = v2 (f [ origin :+ 1, point2 1 1 :+ 100, point2 5 5 :+ 101 ])
--                (f [ point2 1 1 :+ 100, point2 5 5 :+ 101, origin :+ 1 ])
--     output = v2 (f [ origin :+ 0, point2 1 1 :+ 1, point2 5 5 :+ 2 ])
--                 (f [ point2 1 1 :+ 1, point2 5 5 :+ 2, origin :+ 0 ])

--     f = S2.viewL1FromNonEmpty . NonEmpty.fromList . map (&extra %~ ext)

ptSeq = S2.viewL1FromNonEmpty . NonEmpty.fromList . map (&extra %~ ext)

-- coversAll

points1 :: NonEmpty.NonEmpty (Point 2 Double :+ ())
points1 = ext <$> NonEmpty.fromList [point2 0 0, point2 1 1, point2 2 100, point2 3 101]


-- | Computes all pairs of points that are uncovered by the WSPD with separation s
uncovered         :: (Floating r, Ord r, Arity d, Arity (d+1), Ord p)
                  => [Point d r :+ p] -> r -> SplitTree d p r a -> [(Point d r :+ p, Point d r :+ p)]
uncovered pts s t = Set.toList $ allPairs `Set.difference` covered
  where
    allPairs = Set.fromList [ (p,q) | p <- pts, q <- pts, p < q ]
    covered  = Set.unions [ mkSet as bs | (as,bs) <- wellSeparatedPairs s t]

    mkSet as bs = Set.fromList [ (min a b,max a b) | a <- F.toList as, b <- F.toList bs]

-- | Naively check if a WSP pair is actually well separated with respect to
-- separation s. i.e. computes the maximum diameter of as and bs, and then
-- tests by brute force if all pairs (a,b) from different sets are at distance
-- at least s times the maximum diameter.
isWellSeparated           :: (Floating r, Ord r, Arity d) => r -> WSP d p r a -> Bool
isWellSeparated s (as,bs) =
    and [ euclideanDist (a^.core) (b^.core) >= s*r | a <- F.toList as, b <- F.toList bs ]
  where
    r = (/2) . maximum . map (diameterNaive . F.toList) $ [as,bs]



allCoveredTest = describe