Binpack-0.4: Data/BinPack/Internals/SumOfSquares.hs
-- Copyright (c) 2009, Bjoern B. Brandenburg <bbb [at] cs.unc.edu>
--
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
-- * Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
-- * Neither the name of the copyright holder nor the names of any
-- contributors may be used to endorse or promote products derived from
-- this software without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
-- | Sum-of-squares heuristic support.
module Data.BinPack.Internals.SumOfSquares where
import Data.List ( group
, sort
, minimumBy)
import Data.Ord (comparing)
import Data.BinPack.Internals
-- | Sum of squares metric. The sum of the square of the counts of each gap
-- size, ignoring empty and completely-packed bins.
sumOfSquares :: (Num a, Ord a) =>
[Bin a b] -- ^ The bins.
-> Int -- ^ Sum of the squared 'gapCount's.
sumOfSquares = sum
. map sqrlen -- square heuristic
. group . sort -- find bins with equal gaps
. filter (/= 0) -- ignore completely packed bins
. map gap -- determine gap
. filter (not . null . items) -- ignore empty bins
where sqrlen xs = length xs * length xs
-- | Pick a bin that minimizes the sum-of-squares heuristic.
sosfit' :: (Ord a, Num a) =>
Measure a b -> b -> [Bin a b] -> Maybe (Int, [Bin a b])
sosfit' _ _ [] = Nothing
sosfit' size item bins =
let
s = size item
placed = map (\(_,bs) -> (sumOfSquares bs, bs))
. map (\(i,_) -> (i, insertAt i item s bins))
. filter (\(_,b) -> gap b >= s)
. zip [0..]
best = minimumBy (comparing fst)
in
case placed bins of
[] -> Nothing
pl -> Just $ best pl
-- | sosfit, but without the option of adding an additional bin.
sosfitAnyFit :: (Ord a, Num a) => Placement a b
sosfitAnyFit size item = fmap snd . sosfit' size item
-- | sofit, which may add a bin if it lowers the sum-of-squares heuristic.
sosfit :: (Ord a, Num a) => a -> Placement a b
sosfit cap size item bins = fmap testAppend . sosfit' size item $ bins
where
app = bins ++ [makeBin size cap item]
sos = sumOfSquares app
testAppend (sos', bins') = if sos' <= sos then bins' else app