moonlight-planar-1.2.0.0: bench/curve/Moonlight/Planar/RegionBench.hs
-- | New-capability receipts for certified curve topology and proximity on the
-- illustration study's own contours. Certification, plain lowering of the
-- same contours, and the certified lowering that runs both and checks the
-- lowered loops are timed separately, so the certificate's cost reads apart
-- from the lowering's.
module Moonlight.Planar.RegionBench (benchmarks) where
import BenchMeasure (requireRight, timedProjection)
import Control.DeepSeq (force)
import Control.Exception (evaluate)
import Data.Foldable (traverse_)
import qualified Data.Sequence as Seq
import Moonlight.Planar.Affine (identityAffine2)
import Moonlight.Planar.Curve
( ClosedTrail, Located, Subpath (..), closedTrailSteps, locate, locatedValue, openTrail )
import Moonlight.Planar.Curve.Frame (exactTrailSite)
import Moonlight.Planar.Curve.Lowering (LoweringPolicy, loweredSpans, lowerClosedTrail, loweringPolicy)
import Moonlight.Planar.Curve.Measure
( MeasurePolicy, distance, lengthEnclosureLower, lengthEnclosureWidth, measurePolicy
, radicalPrecision, sitePoint )
import Moonlight.Planar.Curve.Proximity
( ClearanceVerdict (..), ContactWitness (..), clearance, curveDistance, distanceBounds
, distanceCandidates )
import Moonlight.Planar.Curve.Region
( CurveComponent (..), SubdivisionBudget, certifiedPieceCounts, certifySimpleRegion
, lowerSimpleRegion, subdivisionBudget )
import Moonlight.Planar.Exact (exactRational, positiveExact, positiveOne, unitZero)
import Moonlight.Planar.Exhibit.IllustrationStudy (StudyPart (..), defaultControls, partContour)
import Moonlight.Planar.Region (planarRegionComponents, polygonHoleLoops)
data RegionFamily
= BladeFuller
| KnightMask
deriving stock (Eq, Show)
benchmarks :: IO ()
benchmarks = do
putStrLn "region-benchmark: new capability; no baseline or speedup claim"
putStrLn "region-benchmark: lowering epsilon=1 identity metric, max-depth=20, max-leaves=8192; topology max-depth=12, max-pieces=4096, max-bits=4096"
putStrLn "region-benchmark: certify = curve certificate alone; lower = plain lowering of the same contours; certified-lowering = both plus the lowered-loop check"
lowering <- requireRight (loweringPolicy positiveOne identityAffine2 20 8192)
topology <- requireRight (subdivisionBudget 12 4096 4096)
traverse_ (benchmarkRegion lowering topology) [BladeFuller, KnightMask]
putStrLn "proximity-benchmark: tolerance=1/100 absolute; radical-precision=64; max-depth=24, max-leaves=20000, max-bits=4096"
measuring <- proximityPolicy
hornBaseClearance measuring
fullerDistance measuring
benchmarkRegion :: LoweringPolicy -> SubdivisionBudget -> RegionFamily -> IO ()
benchmarkRegion lowering topology family = do
let label = "region-" <> show family
components = region family
contours = concatMap (\(CurveComponent outer holes) -> outer : holes) components
pieces = map snd . certifiedPieceCounts
_ <- evaluate (force contours)
evidence <- timedProjection (label <> "-certify") pieces
(requireRight (certifySimpleRegion topology components))
putStrLn (label <> "-certify-receipt: pieces=" <> show (pieces evidence))
lowered <- timedProjection (label <> "-lower") (fmap (length . loweredSpans))
(requireRight (traverse (lowerClosedTrail lowering) contours))
putStrLn (label <> "-lower-receipt: spans=" <> show (length . loweredSpans <$> lowered))
(planar, paths, _) <- timedProjection (label <> "-certified-lowering")
(\(planar, paths, certified) ->
(length . polygonHoleLoops <$> planarRegionComponents planar, length . loweredSpans <$> paths, pieces certified))
(requireRight (lowerSimpleRegion lowering topology components))
putStrLn (label <> "-certified-lowering-receipt: holes=" <> show (length . polygonHoleLoops <$> planarRegionComponents planar)
<> " spans=" <> show (length . loweredSpans <$> paths))
region :: RegionFamily -> [CurveComponent]
region BladeFuller = [CurveComponent (part Blade) [part Fuller]]
region KnightMask = [CurveComponent (part Mask) []]
part :: StudyPart -> Located ClosedTrail
part = partContour defaultControls
proximityPolicy :: IO MeasurePolicy
proximityPolicy = do
tolerance <- requireRight (exactRational 1 100) >>= requireRight . positiveExact
precision <- requireRight (radicalPrecision 64)
measurePolicy tolerance precision <$> requireRight (subdivisionBudget 24 20000 4096)
-- The left horn's base, its closing step, against the mask curve at zero.
hornBaseClearance :: MeasurePolicy -> IO ()
hornBaseClearance measuring = do
let contour = part LeftHorn
source = ClosedSubpath contour
steps = closedTrailSteps (locatedValue contour)
closing = Seq.length steps - 1
start <- requireRight (exactTrailSite source closing unitZero)
base <- maybe (fail "left horn has no closing step") pure (Seq.lookup closing steps)
zero <- requireRight (distance 0)
subject <- evaluate (force (OpenSubpath (locate (sitePoint start) (openTrail (Seq.singleton base))), ClosedSubpath (part Mask)))
verdict <- timedProjection "proximity-HornBase-clearance" id
(requireRight (uncurry (clearance measuring zero) subject))
putStrLn ("proximity-HornBase-clearance-receipt: " <> describe verdict)
where
describe :: ClearanceVerdict -> String
describe verdict = case verdict of
ClearanceHolds enclosure -> "holds lower=" <> show (lengthEnclosureLower enclosure)
ClearanceViolated (CloserThan _ _) -> "violated closer-than"
ClearanceViolated (SharedPoint _ _) -> "violated shared-point"
ClearanceViolated TransversalCrossing {} -> "violated crossing"
ClearanceUnresolved _ candidates obligation -> "unresolved " <> show obligation <> " candidates=" <> show (Seq.length candidates)
-- The fuller's distance from the blade within the tolerance.
fullerDistance :: MeasurePolicy -> IO ()
fullerDistance measuring = do
subject <- evaluate (force (ClosedSubpath (part Fuller), ClosedSubpath (part Blade)))
observation <- timedProjection "proximity-FullerBlade-distance" id
(requireRight (uncurry (curveDistance measuring) subject))
let enclosure = distanceBounds observation
putStrLn ("proximity-FullerBlade-distance-receipt: lower=" <> show (lengthEnclosureLower enclosure)
<> " width=" <> show (lengthEnclosureWidth enclosure)
<> " candidates=" <> show (Seq.length (distanceCandidates observation)))