{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
module ProductMixAuction.LP.AdditionalConstraint
( AdditionalConstraint(..)
, mkAbsoluteQuantityConstraint
, mkRelativeQuantityConstraint
, showConstraint
, mapConstraint
, ac_c
, ac_c'
, ac_coefficients
) where
import Control.Lens
import Data.Aeson
import Data.Default.Class
import Data.List
import qualified Data.Map as Map
import GHC.Generics
import ProductMixAuction.Types
data AdditionalConstraint bid =
AdditionalConstraint
{ _ac_coefficients :: Map.Map bid (Map.Map Good Double)
, _ac_c :: Ratio
, _ac_c' :: Double
}
deriving (Generic, Show)
instance (FromJSONKey bid, Ord bid) => FromJSON (AdditionalConstraint bid)
where parseJSON = genericParseJSON $ jsonOptions "_ac_"
instance ToJSONKey bid => ToJSON (AdditionalConstraint bid)
where toJSON = genericToJSON $ jsonOptions "_ac_"
instance Default (AdditionalConstraint bid) where
def = AdditionalConstraint Map.empty 1 0
mkAbsoluteQuantityConstraint :: Ord bid => [Good] -> [bid] -> Units -> AdditionalConstraint bid
mkAbsoluteQuantityConstraint goods bids u = AdditionalConstraint coeffs 0 (_Units u)
where
m = Map.fromList (map (\ g -> (g, 1)) goods)
coeffs = Map.fromList (map (\ b -> (b, m)) bids)
mkRelativeQuantityConstraint :: Ord bid => [Good] -> [bid] -> Ratio -> AdditionalConstraint bid
mkRelativeQuantityConstraint goods bids r = AdditionalConstraint coeffs r 0
where
m = Map.fromList (map (\ g -> (g, 1)) goods)
coeffs = Map.fromList (map (\ b -> (b, m)) bids)
showConstraint :: Show bid => AdditionalConstraint bid -> String
showConstraint ac = summands as ++ " <= " ++ summands [showy (_ac_c ac) "R", showy (_ac_c' ac) "1"]
where
as = [ showy x ("Alloc(" ++ show bid ++ "," ++ show good ++ ")")
| (bid, gxs) <- Map.toList (_ac_coefficients ac)
, (good, x) <- Map.toList gxs
]
showy x s
| x == 0 = []
| s == "1" = [show x]
| x == 1 = [s]
| otherwise = [show x ++ " * " ++ s]
summands xs = intercalate " + " (concat xs)
$(makeLenses ''AdditionalConstraint)
-- | Change the representation of bid labels in an additional constraint.
-- Requires the codomain to have an 'Ord' instance, hence not a 'Functor'.
mapConstraint :: Ord bid' => (bid -> bid') -> AdditionalConstraint bid -> AdditionalConstraint bid'
mapConstraint f = over ac_coefficients (Map.mapKeys f)