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