product-mix-auction-0.1.0.0: A single-round sealed-bid auction for multiple goods

Safe HaskellNone
LanguageHaskell2010

ProductMixAuction.DotBids

Contents

Description

Dot-Bid Auctions. A dot-bid auction is an auction where goods are sold at integral quantities (often even unit quantities, although this is not a requirement), and bidders are generally interested in a given quantity of any of a set of alternative goods. That is, bidders want to express their interest in buying N units of either good A at price P, or good B at price Q, or good C at price R, etc., but only one of those options. There is a fixed supply of each good available, and the algorithm will find the lowest price at which this supply (or more) will be demanded completely.

Examples of goods for which this auction type is suitable include:

  • FM radio frequencies: each bidder is typically only interested in one frequency, but they will want to place bids on more than one of them, because their preferred one might be so popular that they lose the auction; but putting in two separate bids could have them end up with two frequencies when they only need one.
  • A government buying bad loans against a choice of collaterals. Here the situation is reversed, as the auctioneer is *buying* loans; however, the mechanism is exactly the same.

Throughout the code, we are referencing the paper "Finding a valid allocation" (Baldwin, Goldberg, Klemperer 2017) (sometimes referred to as "validityAllocation"); much of the terminology used here is derived from that paper.

If you are not interested in the implementation, and just want to run an auction, the following will be sufficient:

The REJECT good receives special treatment in the paper; it is a virtual good that represents rejecting bids, that is, allocating on REJECT means that we are rejecting bids, and finding a nonzero value in the REJECT element of the resulting endowment means that not all the bidder's bids have been honored.

Just like in the paper, we extend all inputs (bids, target bundle, reserve price) with an additional REJECT coordinate, which we maintain throughout the entire processing chain, to remove it again only at the very last step. In other words, the problem is presented without the REJECT good on the outside, but the REJECT coordinate is consistently present on the inside. So, for an auction of 4 goods, we will see 4-dimensional vectors in the input and output, but 5-dimensional vectors in all the internal functions.

The paper makes frequent use of sets; however, the operations performed on them are often such that it is more efficient to represent them as vectors where each component is either 0 or 1. Represented like this, set operations become vector operations, e.g.:

set union -> component-wise maximum
set intersection -> component-wise minimum
set membership test -> component lookup + nonzero test

Synopsis

Basic Types

newtype Price Source #

Represents a price supplied by or presented to the user.

Constructors

Price 

Fields

Instances

Enum Price Source # 
Eq Price Source # 

Methods

(==) :: Price -> Price -> Bool #

(/=) :: Price -> Price -> Bool #

Integral Price Source # 
Num Price Source # 
Ord Price Source # 

Methods

compare :: Price -> Price -> Ordering #

(<) :: Price -> Price -> Bool #

(<=) :: Price -> Price -> Bool #

(>) :: Price -> Price -> Bool #

(>=) :: Price -> Price -> Bool #

max :: Price -> Price -> Price #

min :: Price -> Price -> Price #

Read Price Source # 
Real Price Source # 

Methods

toRational :: Price -> Rational #

Show Price Source # 

Methods

showsPrec :: Int -> Price -> ShowS #

show :: Price -> String #

showList :: [Price] -> ShowS #

Generic Price Source # 

Associated Types

type Rep Price :: * -> * #

Methods

from :: Price -> Rep Price x #

to :: Rep Price x -> Price #

ToJSON Price Source # 

Methods

toJSON :: Price -> Value

toEncoding :: Price -> Encoding

toJSONList :: [Price] -> Value

toEncodingList :: [Price] -> Encoding

FromJSON Price Source # 

Methods

parseJSON :: Value -> Parser Price

parseJSONList :: Value -> Parser [Price]

ToField Price Source # 

Methods

toField :: Price -> Field

FromField Price Source # 

Methods

parseField :: Field -> Parser Price

Default Price Source # 

Methods

def :: Price

Random Price Source # 

Methods

randomR :: RandomGen g => (Price, Price) -> g -> (Price, g)

random :: RandomGen g => g -> (Price, g)

randomRs :: RandomGen g => (Price, Price) -> g -> [Price]

randoms :: RandomGen g => g -> [Price]

randomRIO :: (Price, Price) -> IO Price

randomIO :: IO Price

type Rep Price Source # 
type Rep Price = D1 (MetaData "Price" "ProductMixAuction.DotBids" "product-mix-auction-0.1.0.0-inplace" True) (C1 (MetaCons "Price" PrefixI True) (S1 (MetaSel (Just Symbol "_Price") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Integer)))

newtype Units Source #

In dot-bids auctions, quantities are always integers (discrete rather than continuous) but may be negative.

Constructors

Units 

Fields

Instances

Enum Units Source # 
Eq Units Source # 

Methods

(==) :: Units -> Units -> Bool #

(/=) :: Units -> Units -> Bool #

Integral Units Source # 
Num Units Source # 
Ord Units Source # 

Methods

compare :: Units -> Units -> Ordering #

(<) :: Units -> Units -> Bool #

(<=) :: Units -> Units -> Bool #

(>) :: Units -> Units -> Bool #

(>=) :: Units -> Units -> Bool #

max :: Units -> Units -> Units #

min :: Units -> Units -> Units #

Real Units Source # 

Methods

toRational :: Units -> Rational #

Show Units Source # 

Methods

showsPrec :: Int -> Units -> ShowS #

show :: Units -> String #

showList :: [Units] -> ShowS #

Generic Units Source # 

Associated Types

type Rep Units :: * -> * #

Methods

from :: Units -> Rep Units x #

to :: Rep Units x -> Units #

ToJSON Units Source # 

Methods

toJSON :: Units -> Value

toEncoding :: Units -> Encoding

toJSONList :: [Units] -> Value

toEncodingList :: [Units] -> Encoding

FromJSON Units Source # 

Methods

parseJSON :: Value -> Parser Units

parseJSONList :: Value -> Parser [Units]

ToField Units Source # 

Methods

toField :: Units -> Field

FromField Units Source # 

Methods

parseField :: Field -> Parser Units

Default Units Source # 

Methods

def :: Units

type Rep Units Source # 
type Rep Units = D1 (MetaData "Units" "ProductMixAuction.DotBids" "product-mix-auction-0.1.0.0-inplace" True) (C1 (MetaCons "Units" PrefixI True) (S1 (MetaSel (Just Symbol "_Units") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Integer)))

type Good = Int Source #

Goods are numbered from 0 to N-1, where N is the dimension of the auction.

type Bundle = Vector Units Source #

A bundle of goods (i.e. a quantity for each good).

type PriceVector = Vector Price Source #

A vector in price space (i.e. a price for each good).

emptyBundle :: Dimension -> Bundle Source #

The bundle containing no goods.

isSubBundle :: Bundle -> Bundle -> Bool Source #

Test whether the first bundle is a sub-bundle of the second (i.e. it contains less of each good).

priceOf :: Good -> Vector a -> a Source #

Find the price of a single good.

addToPrice :: Num price => Good -> price -> Vector price -> Vector price Source #

Increment the price of a single good.

mulUnitPrice :: Num a => Units -> a -> a Source #

Helper functions for dealing with Vectors and Lists

modifyAt :: Int -> (a -> a) -> Vector a -> Vector a Source #

Modify the i-th component of a vector.

generate :: IsList l => Int -> (Int -> Item l) -> l Source #

generate n f generates a list-like data structure containing n items, such that item n equals f n.

extend :: Num a => Vector a -> Vector a Source #

Prepend a 0th element of value 0 to a vector. This is effectively an implementation of the ι function described in Algorithm 1, step 2.

reduce :: Vector a -> Vector a Source #

Dual to extend: removes the first element from a vector.

zero0 :: Num a => Vector a -> Vector a Source #

Explicitly set the 0th element of a vector to 0. Several algorithms require this step

dimension :: Vector a -> Int Source #

Get the dimension of a vector. Right now, it is just an alias for length.

(!?) :: Vector a -> Int -> a Source #

Get the n-th element from a vector, 0-based. This used to be important when the codebase still had 1-based vectors with implicit 0th elements, but now that this distinction has been removed, this is just an alias for !.

argmin :: Ord b => (a -> b) -> [a] -> a Source #

argmax :: Ord b => (a -> b) -> [a] -> a Source #

opt :: (Num a, Ord a) => Vector a -> Vector a -> (a, Vector a) Source #

The opt function frequently used in the validityAllocation paper: given vectors p and v, find the goods on which p - v is maximal, and return the maximal value and a vector representing the set of goods on which the difference is maximal.

Informally, this gets us the best price relative to the target price.

exceedsUpperBound :: (Foldable f, ComponentWise f, Ord a) => f a -> f a -> Bool Source #

exceedsLowerBound :: (Foldable f, ComponentWise f, Ord a) => f a -> f a -> Bool Source #

unitWhereLower :: (Ord a, ComponentWise f, Functor f, Num b) => f a -> f a -> f b Source #

unitWhereLower a b gets a vector v such that v[n] = 1 if a[n] < b[n], else 0.

powersetL :: [a] -> [[a]] Source #

Find the powerset of a set, implemented using lists.

powerset :: Ord a => Set a -> [Set a] Source #

Find the powerset of a set.

eSet :: Num a => Good -> Set Good -> Vector a Source #

Create a unit vector from a set of coordinates.

ePowerset :: Num a => Good -> Set Good -> [Vector a] Source #

Find the powerset of the set of N goods, represented as a list of vectors such that for each good in the set, the corresponding vector's coordinate is set to 1, while for each good not in the set, the vector's coordinate is set to 0.

eXs :: forall f a. (IsList (f a), Item (f a) ~ a, Num a) => Dimension -> [f a] Source #

eX, from section 3 of "LP for dot-bids, and usage of the Ellipsoid Method", used in several of the algorithms described there.

For X ⊂ [N] write eX for the vector defined by (eX)i = 1 iff i ∈ X, (eX)i = 0 otherwise.

For efficiency reasons, instead of calculating individual eX for a given subset X of [N], and considering the use cases, we implement instead a function eXs, that enumerates *all* the possible eX for a given N.

eXs1 :: Dimension -> [PriceVector] Source #

A variation of eXs that does not include the zero vector.

eX :: (IsList (f price), Item (f price) ~ price, Num price) => Dimension -> Dimension -> f price Source #

Bidders and Bid Agents

data BidAgentID b Source #

Identifies a bid agent. A bid agent can be either a real Bidder, or the Auctioneer, who will buy all the unsold goods in the auction back at any price.

Constructors

Auctioneer

The auctioneer, used to identify auctioneer bids.

Bidder b

A regular, "real" bidder.

Instances

Eq b => Eq (BidAgentID b) Source # 

Methods

(==) :: BidAgentID b -> BidAgentID b -> Bool #

(/=) :: BidAgentID b -> BidAgentID b -> Bool #

Ord b => Ord (BidAgentID b) Source # 
Show b => Show (BidAgentID b) Source # 
Generic (BidAgentID b) Source # 

Associated Types

type Rep (BidAgentID b) :: * -> * #

Methods

from :: BidAgentID b -> Rep (BidAgentID b) x #

to :: Rep (BidAgentID b) x -> BidAgentID b #

(ToJSON b, ToJSONKey b) => ToJSONKey (BidAgentID b) Source # 

Methods

toJSONKey :: ToJSONKeyFunction (BidAgentID b)

toJSONKeyList :: ToJSONKeyFunction [BidAgentID b]

ToJSON b => ToJSON (BidAgentID b) Source # 

Methods

toJSON :: BidAgentID b -> Value

toEncoding :: BidAgentID b -> Encoding

toJSONList :: [BidAgentID b] -> Value

toEncodingList :: [BidAgentID b] -> Encoding

(FromJSON b, FromJSONKey b) => FromJSONKey (BidAgentID b) Source # 

Methods

fromJSONKey :: FromJSONKeyFunction (BidAgentID b)

fromJSONKeyList :: FromJSONKeyFunction [BidAgentID b]

FromJSON b => FromJSON (BidAgentID b) Source # 

Methods

parseJSON :: Value -> Parser (BidAgentID b)

parseJSONList :: Value -> Parser [BidAgentID b]

ToField b => ToField (BidAgentID b) Source # 

Methods

toField :: BidAgentID b -> Field

FromField b => FromField (BidAgentID b) Source # 

Methods

parseField :: Field -> Parser (BidAgentID b)

type Rep (BidAgentID b) Source # 
type Rep (BidAgentID b) = D1 (MetaData "BidAgentID" "ProductMixAuction.DotBids" "product-mix-auction-0.1.0.0-inplace" False) ((:+:) (C1 (MetaCons "Auctioneer" PrefixI False) U1) (C1 (MetaCons "Bidder" PrefixI False) (S1 (MetaSel (Nothing Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 b))))

Bids

data DotBidOf b a Source #

A dot-bid is represented by a number of units (which may be positive or negative) and a vector of prices for each good.

Constructors

DotBid 

Instances

Functor (DotBidOf b) Source # 

Methods

fmap :: (a -> b) -> DotBidOf b a -> DotBidOf b b #

(<$) :: a -> DotBidOf b b -> DotBidOf b a #

(Eq b, Eq a) => Eq (DotBidOf b a) Source # 

Methods

(==) :: DotBidOf b a -> DotBidOf b a -> Bool #

(/=) :: DotBidOf b a -> DotBidOf b a -> Bool #

(Show b, Show a) => Show (DotBidOf b a) Source # 

Methods

showsPrec :: Int -> DotBidOf b a -> ShowS #

show :: DotBidOf b a -> String #

showList :: [DotBidOf b a] -> ShowS #

(ToJSON b0, ToJSON a0) => ToJSON (DotBidOf b0 a0) Source # 

Methods

toJSON :: DotBidOf b0 a0 -> Value

toEncoding :: DotBidOf b0 a0 -> Encoding

toJSONList :: [DotBidOf b0 a0] -> Value

toEncodingList :: [DotBidOf b0 a0] -> Encoding

(FromJSON b0, FromJSON a0) => FromJSON (DotBidOf b0 a0) Source # 

Methods

parseJSON :: Value -> Parser (DotBidOf b0 a0)

parseJSONList :: Value -> Parser [DotBidOf b0 a0]

(ToField b, ToField a) => ToRecord (DotBidOf b a) Source # 

Methods

toRecord :: DotBidOf b a -> Record

dotBidQuantity :: forall b a. Lens' (DotBidOf b a) Units Source #

dotBidPrices :: forall b a a. Lens (DotBidOf b a) (DotBidOf b a) (Vector a) (Vector a) Source #

dotBidAgentID :: forall b a b. Lens (DotBidOf b a) (DotBidOf b a) (BidAgentID b) (BidAgentID b) Source #

Calculating Demand

maximumPrices :: (Ord price, Num price) => Dimension -> [DotBidOf b price] -> Vector price Source #

Calculate the maximum price bid on each good.

bidsByAgents :: forall a b. (Eq b, Ord b) => [DotBidOf b a] -> Map (BidAgentID b) [DotBidOf b a] Source #

Sort a list of bids into a Map indexed by bid agent. We will be using this in algorithms that require us to only look at the set of bids from one specific bid agent.

replaceAgentBids :: Eq b => BidAgentID b -> [DotBidOf b a] -> [DotBidOf b a] -> [DotBidOf b a] Source #

replaceAgentBids agentID bidsToKeep bids removes all bids for agent agentID from the list of bids, and then inserts all the bids in bidsToKeep. The bids in bidsToKeep should all be from the bidder indicated by agentID, however this is not enforced.

separateBidsAcrossGoodsMin :: [DotBid b] -> PriceVector -> [[DotBid b]] Source #

Algorithm 2 from validityAllocation: Separate bids across goods at p, minimizing demand.

separateBidsAcrossGoodsMax :: [DotBid b] -> PriceVector -> [[DotBid b]] Source #

Algorithm 3 from validityAllocation: Separate bids across goods at p, maximizing demand.

bundleDemandedMin :: [DotBid b] -> PriceVector -> Bundle Source #

Algorithm 4 from validityAllocation: Calculate a bundle demanded at p, minimizing demand (via Algorithm 2 / separateBidsAcrossGoodsMin)

bundleDemandedMax :: [DotBid b] -> PriceVector -> Bundle Source #

Algorithm 4 from validityAllocation: Calculate a bundle demanded at p, maximizing demand (via Algorithm 2 / separateBidsAcrossGoodsMax)

bundlesDemandedApprox :: Eq b => [DotBid b] -> PriceVector -> [Bundle] Source #

Calculates an overestimation of bundles demanded at a given price point.

Not all bundles returned are guaranteed to be actually demanded at the price point, but any bundle that is actually demanded is guaranteed to be in the returned set.

The approximation is calculated based on marginality: - bids that are non-marginally accepted at the price point are always selected on the good that they are accepted on - for each bid that is marginal on any goods (including REJECT), bundles are explored that select the bid on each of the goods that it is marginal on - any other bid (neither non-marginally accepted nor marginal) is ignored

setAuctioneerBids :: (Num a, Eq b) => Bundle -> [DotBidOf b a] -> [DotBidOf b a] Source #

Add auctioneer bids to an auction, replacing any existing auctioneer bids. Needed for Algorithm 1.

auctioneerBids :: Num a => Bundle -> [DotBidOf b a] Source #

Calculate auctioneer bids for a bundle. Needed for Algorithm 1.

auctioneerBidOn :: Num a => Good -> Bundle -> DotBidOf b a Source #

Calculate the auctioneer bid for a given good and bundle. Needed for Algorithm 1.

Calculating marginality

hasNoMarginalBids :: [DotBid b] -> PriceVector -> Bool Source #

Checks if the price vector has no marginal bids.

marginalBidsOn :: (Num a, Ord a) => Good -> Vector a -> [DotBidOf b a] -> [DotBidOf b a] Source #

Get all bids marginal on a given good at a given price vector. See Algorithm 5 in validityAllocation.pdf.

marginalBids :: (Num a, Ord a) => Vector a -> [DotBidOf b a] -> [[DotBidOf b a]] Source #

Get all bids marginal on any good at the given price vector.

isMarginalOn :: (Num a, Ord a) => Good -> Vector a -> DotBidOf b a -> Bool Source #

Check if a bid is marginal on a given good at a given price vector. See Algorithm 5 in validityAllocation.pdf.

nonMarginallyAcceptedBids :: [DotBid b] -> PriceVector -> [[DotBid b]] Source #

Algorithm 10 from validityAllocation.pdf: Identify bids non-marginally accepted on each good (including REJECT)

nonMarginallyAcceptedBidsOn :: (Num a, Ord a) => Good -> [DotBidOf b a] -> Vector a -> [DotBidOf b a] Source #

Identify bids non-marginally accepted on a given good.

isNonMarginallyAcceptedOn :: (Num a, Ord a) => Good -> Vector a -> DotBidOf b a -> Bool Source #

Check if a bid is non-marginally accepted on a given good.

anyMarginalOn :: (Num a, Ord a) => Good -> Vector a -> [DotBidOf b a] -> Bool Source #

Check if any bids are marginal on the given good.

biddersMarginalOn :: (Num a, Ord a, Ord b) => [DotBidOf b a] -> Vector a -> Good -> Set (BidAgentID b) Source #

List all unique bidders that are marginal on a given good at a given price point.

Finding an equilibrium price

Calculating g, the function to be minimised

calcUG :: forall a b. (Num a, Ord a) => [DotBidOf b a] -> Vector Units -> Vector a -> (a, a) Source #

Calculate u and g, as shown in Lemma 3 in section 3.3 of "LP for dot-bits, and usage of the Ellipsoid Method".

For a given set of bids and a target bundle, minimising g gives the price vector at which the target bundle is demanded.

Returns the value of u in the first component, and the value of g in the second component.

calcU :: (Num a, Ord a) => [DotBidOf b a] -> Vector Units -> Vector a -> a Source #

Calculate u only.

calcG :: (Num a, Ord a) => [DotBidOf b a] -> Vector Units -> Vector a -> a Source #

Calculate g only.

vpart :: forall a b. (Num a, Ord a) => Good -> Vector a -> [DotBidOf b a] -> [DotBidOf b a] Source #

Given a good j and a price vector prices, this computes the set V_j(prices) from Definition 5 in Section 3.3 from a list of dot bids.

A dot bid will end up in (at most) one of the V_j sets, where j indicates the good which is demanded by this bid. If multiple goods are equally close to the bid, then we put the bid in the set for the good with the lowest index.

Minimizing g

validTarget :: [DotBid b] -> Bundle -> Bool Source #

Check that the given target bundle is a sub-bundle of the bundle demanded at the origin. If this is not the case, the search algorithms may return an invalid result or fail to terminate.

findBundleNaive :: [DotBid b] -> Bundle -> PriceVector Source #

Find prices that cause the given bundle to be demanded.

This uses a brute-force search for the minimum of g across all prices.

findBundle :: (Eq b, Show b) => [DotBid b] -> Bundle -> PriceVector Source #

Find prices that cause the given bundle to be demanded. The validTarget predicate should be satisfied to make sure this doesn't loop.

findBundle_GreedyUpMinimal :: (Num a, Ord a, Show a, Integral a, Eq b, Show b) => [DotBidOf b a] -> Bundle -> Vector a Source #

Find prices that cause the given bundle to be demanded.

This implementation uses the GreedyUpMinimal algorithm described in section 3 of "LP for dot-bids, and usage of the Ellipsoid Method", also described as Algorithm 8 in validityAllocation.

findBundle_GreedyUpMinimalM Source #

Arguments

:: (Monad m, Ord a, Num a, Show a, Eq b, Show b) 
=> (String -> m ())

trace function

-> ([DotBidOf b a] -> Vector a -> Bundle -> Vector a)

find local minimum

-> [DotBidOf b a]

bids

-> Bundle

target bundle

-> m (Vector a) 

Flavor of findBundle_GreedyUpMinimal with tracing, in an arbitrary Monad.

findBundle_TwoPhaseMinMin :: Eq b => PriceVector -> [DotBid b] -> Bundle -> PriceVector Source #

Find prices that cause the given bundle to be demanded.

This implementation uses the TwoPhaseMinMin algorithm described in section 3 of "LP for dot-bids, and usage of the Ellipsoid Method". The same algorithm is also described in validityAllocation as Algorithm 9.

findBundle_TwoPhaseMinMinM :: forall m b. (Eq b, Monad m) => (String -> m ()) -> PriceVector -> [DotBid b] -> Bundle -> m PriceVector Source #

Flavor of findBundle_TwoPhaseMinMin with tracing, in an arbitrary Monad.

findBundle_TwoPhaseMinMaxM :: forall m b. (Eq b, Monad m) => (String -> m ()) -> PriceVector -> [DotBid b] -> Bundle -> m PriceVector Source #

Flavor of findBundle_TwoPhaseMinMin with tracing, in an arbitrary Monad.

findBundle_TwoPhaseM :: forall m b. (Eq b, Monad m) => ((Vector Price -> Price) -> (Vector Price -> Price) -> [PriceVector] -> Vector Price) -> (String -> m ()) -> PriceVector -> [DotBid b] -> Bundle -> m PriceVector Source #

Base implementation of the TwoPhase algorithms, with tracing.

minimalMinimizer :: (Ord a, Ord b) => (a -> b) -> [a] -> a Source #

minimalMinimizer p xs finds the smallest x in xs for which p x is minimal.

minimalMinimizerBy :: (Ord a, Ord b) => (c -> a) -> (c -> b) -> [c] -> c Source #

minimalMinimizerBy f p xs finds x' in xs' such that xs' is the set of x for which p x is minimal, and f x' is minimal in xs'.

maximalMinimizer :: (Ord a, Ord b) => (a -> b) -> [a] -> a Source #

maximalMinimizer p xs finds the smallest x in xs for which p x is maximal.

maximalMinimizerBy :: (Ord a, Ord b) => (c -> a) -> (c -> b) -> [c] -> c Source #

maximalMinimizerBy f p xs finds x' in xs' such that xs' is the set of x for which p x is minimal, and f x' is maximal in xs'.

allPriceVectors :: PriceVector -> PriceVector -> [PriceVector] Source #

List all the prices contained in the hyperrectangle with given bottom-left and top-right corners.

upperBidBounds :: Ord a => [DotBidOf b a] -> Maybe (Vector a) Source #

Get the upper limit of bid prices per dimension, like upperPriceBounds, but for DotBids, not PriceVectors.

upperPriceBounds :: Ord a => [Vector a] -> Maybe (Vector a) Source #

Get the upper limit of prices per dimension. E.g., for bids [ (1, 10), (5, 5), (9, 2) ], the upper limit is (9, 10).

Empty input returns Nothing.

findIK :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Bundle -> (Vector a, Vector a) Source #

Algorithm 11 from validityAllocation.pdf: Identify I and K as in Proposition 4.4. Needed for Algorithms 12 and 13 (optimized minimal/maximal minimizers)

minminCandidates' :: (Num a, Ord a) => [Vector a] -> [DotBidOf b a] -> Vector a -> Bundle -> [Vector a] Source #

Algorithm 12 from the validityAllocation.pdf document. This doesn't implement all of Algorithm 12, rather it just filters a given list of candidates according to the conditions outlined in the last section (such that...). Finding the actual minimal minimizer is already handled in the crawler algorithm itself, and other filters are applied there already, so we do not duplicate this here.

minminCandidates :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Bundle -> [Vector a] Source #

maxminCandidates' :: (Num a, Ord a) => [Vector a] -> [DotBidOf b a] -> Vector a -> Bundle -> [Vector a] Source #

Algorithm 13 from the validityAllocation.pdf document. This doesn't implement all of Algorithm 13, rather it just filters a given list of candidates according to the conditions outlined in the last section (such that...). Finding the actual minimal minimizer is already handled in the crawler algorithm itself, and other filters are applied there already, so we do not duplicate this here.

maxminCandidates :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Bundle -> [Vector a] Source #

jumpDistUp :: forall a b. (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Vector a -> a Source #

λ p x from the validityAllocation.pdf paper, used in Algorithm 14.

jumpDistDown :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Vector a -> a Source #

ν p x from the validityAllocation.pdf paper, used in Algorithm 15.

minimalNeighbour :: (Num a, Ord a, Integral a, Show a, Show b) => [DotBidOf b a] -> Vector a -> Bundle -> Vector a Source #

minimalNeighbourBF :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Bundle -> Vector a Source #

Brute-force way of finding a minimal neighbour.

minimalNeighbourFW :: forall a b. (Num a, Ord a, Integral a) => [DotBidOf b a] -> Vector a -> Bundle -> Vector a Source #

Find minimal neighbour via Fujishige-Wolfe algorithm.

minimalNeighbourBoth :: forall a b. (Num a, Ord a, Integral a, Show a, Show b) => [DotBidOf b a] -> Vector a -> Bundle -> Vector a Source #

Helper functions for constructing bids, bundles, and price vectors.

mkBid :: Units -> Vector a -> BidAgentID b -> DotBidOf b a Source #

Generating sets of valid bids

generateValidBids :: Integer -> Int -> Int -> BidAgentID b -> Gen ([PriceVector], [DotBid b]) Source #

This implements the previous version of the valid bids generation procedure as shown in section 3.1 in "Valid Combinations of Bids", where all bid weights are 1. For a generalized version as described in a newer version of the same paper, which produces randomly weighted bids, see generateValidBidsW.

generateValidBidsW :: Integer -> Integer -> Int -> Int -> BidAgentID b -> Gen ([PriceVector], [DotBid b]) Source #

This implements the valid bids generation procedure as shown in section 3.1 in "Valid Combinations of Bids". This flavor produces randomly weighted bids; set maxWeight to 1 to disable this behavior, or use generateValidBids instead.

generateHorribleValidBidsW :: Integer -> Integer -> Int -> BidAgentID b -> Gen ([PriceVector], [DotBid b]) Source #

A variation on the generateValidBidsW function that intentionally generates bids sets that "line up with each other in a horrible way".

Allocating goods to bidders

Representing the Allocation Problem

data AllocationProblemOf b a Source #

An allocation problem is defined as:

  1. An equilibrium price vector, found using one of the findBundle functions (named p in the paper).
  2. Bids, including auctioneer bids (named V in the paper).
  3. Bid weights (implemented as the _dotBidQuantity field of the DotBidOf data structure; named w in the paper).
  4. Such that for each bidder (j ∈ J in the paper), the set of bids for that bidder is P-valid.
  5. An endowment map, associating each bidder with a bundle allocated to that bidder (m in the paper).
  6. A residual supply (r in the paper), initialized to the target bundle (t in the paper) but, over the course of resolving the problem, to be reduced to all-zero if possible.
  7. Additionally, we track a set of active goods, that is, all the goods that haven't been resolved fully.

Allocation problems are polymorphic on a bidder ID type, b, and a price type, a. The latter is necessary because some parts of the algorithm require fractional prices (specifically, half-unit prices).

apBids :: forall b a. Lens' (AllocationProblemOf b a) [DotBidOf b a] Source #

apActiveGoods :: forall b a. Lens' (AllocationProblemOf b a) (Set Good) Source #

apPrice :: forall b a. Lens' (AllocationProblemOf b a) (Vector a) Source #

Operations on Allocation Problems

isVacuous :: AllocationProblemOf b a -> Bool Source #

An allocation problem is considered vacuous if any of the following hold true:

  1. there are no more bids to consider
  2. there is no residual supply left to allocate
  3. there are no more active goods in the active goods set

When an allocation problem is vacuous, we can assume that no further processing is desired.

totalGoods :: AllocationProblemOf b a -> Bundle Source #

The total number of units per good in a given allocation problem, i.e., the sum of all allocated goods plus the residual supply.

Preparing Allocation Problems from bids and target bundles

mkAllocationProblem :: (Eq b, Show b) => [DotBid b] -> Bundle -> AllocationProblem b Source #

Create an initial allocation problem from a set of bids and a target bundle (initial supply).

mkAllocationProblemEx Source #

Arguments

:: (Eq b, Monad m) 
=> (String -> m ())

Trace logger

-> PriceVector

Auctioneer reserve price

-> ((String -> m ()) -> [DotBid b] -> Bundle -> m PriceVector)

Equilibrium finder

-> [DotBid b]

Bids

-> Bundle

Available supply (target bundle)

-> m (AllocationProblem b) 

Fully configurable preparation of an allocation problem.

Generating random Allocation Problems

genAllocationProblem :: Integer -> Integer -> Int -> Int -> Int -> Gen (AllocationProblem Int) Source #

Generate a valid allocation problem with multiple bidders.

genHorribleAllocationProblem :: Integer -> Integer -> Int -> Int -> Gen (AllocationProblem Int) Source #

Generate a "horrible" (but valid) allocation problem with multiple bidders.

Invariants

check :: Monad m => String -> Bool -> m () Source #

The Obvious Refinement

allocateObvious :: forall a b m. (Num a, Ord a, Monad m, Show a, Ord b, Show b) => StateT (AllocationProblemOf b a) m () Source #

Apply the Obvious Refinement defined in section 6.2 of the validityAllocation paper.

Loosely following Algorithm 16.

allocateObviousL :: forall a b m. (Num a, Ord a, Show a, Ord b, Show b, Monad m) => (String -> m ()) -> StateT (AllocationProblemOf b a) m () Source #

Flavor of allocateObvious with monadic trace logging.

Key Lists and Link Goods

findKeyList :: (Num a, Ord a) => [DotBidOf b a] -> Vector a -> Good -> Set Good Source #

Find a key list within a set of bids, starting at a given good that is assumed to be marginal for at least one bid at the given price vector p.

The given bids are assumed to all belong to the same bidder.

A key list is a set of at least two goods and exactly one bidder, such that the goods form the nodes of a maximally connected subgraph of the marginal bids graph for the given bids and price vector.

Unlike Algorithm 18 described in validityAllocation, we return only the goods that make up a key list, not the bidder, which is implicitly assumed to be the only bidder in the list of given bids.

Also unlike Algorithm 18, we return a singleton set if the given good is not part of a key list; consumers who wish to treat this case specially will have to perform the relevant checks themselves.

isLinkGood :: (Num a, Ord a, Ord b) => [DotBidOf b a] -> Vector a -> Good -> Bool Source #

Determine whether a good is a link good at the specified price point, as per Definition 6.6 and Algorithm 17 in the validityAllocation paper.

A good is considered a link good iff the number of distinct bidders marginal on this good at the given price point exceeds 1, or, in terms of the Marginal Goods Graph, iff it has edges labelled by more than one bidder.

Key List Allocation

allocateByKeyList :: (Num a, Ord a, Show a, Ord b, Show b, Monad m) => BidAgentID b -> Set Good -> StateT (AllocationProblemOf b a) m () Source #

Allocate to key list goods, if possible, as described in Algorithm 19 in validityAllocation.

allocateByKeyListL :: forall a b m. (Num a, Ord a, Show a, Ord b, Show b, Monad m) => (String -> m ()) -> BidAgentID b -> Set Good -> StateT (AllocationProblemOf b a) m () Source #

allocateByKeyList with tracing in an arbitrary Monad.

Jiggles

jiggleBids :: Eq b => BidAgentID b -> Good -> [DotBidOf b Frac2] -> [DotBidOf b Frac2] Source #

A jiggle, as per definition 7.2 in the validityAllocation paper.

jiggleBid :: Good -> DotBidOf b Frac2 -> DotBidOf b Frac2 Source #

Jiggle an individual bid.

jiggle :: (Monad m, Show b, Eq b) => Good -> BidAgentID b -> StateT (AllocationProblemOf b Frac2) m () Source #

A single (i*, j*) jiggle, as described in Algorithm 20 in validityAllocation.

jiggleL :: (Monad m, Show b, Eq b) => (String -> m ()) -> Good -> BidAgentID b -> StateT (AllocationProblemOf b Frac2) m () Source #

jiggle with tracing in an arbitrary Monad.

moveBid :: Num a => Vector a -> DotBidOf b a -> DotBidOf b a Source #

unjiggleBid :: (Num a, Fractional a, Show b, Eq b) => Good -> BidAgentID b -> DotBidOf b a -> DotBidOf b a Source #

Projection Preserving Marginality

ppm :: (Num a, Ord a, Monad m) => StateT (AllocationProblemOf b a) m () Source #

The Projection Preserving Marginality as described in Algorithm 21 of the validityAllocation paper, applied to all bids in an allocation problem.

ppmBids :: (Num a, Ord a) => Vector a -> [DotBidOf b a] -> [DotBidOf b a] Source #

The Projection Preserving Marginality as described in Algorithm 21 of the validityAllocation paper, applied to a list of bids.

ppmBid :: (Num a, Ord a) => Vector a -> DotBidOf b a -> DotBidOf b a Source #

The Projection Preserving Marginality as described in Algorithm 21 of the validityAllocation paper, applied to a single bid.

ppmPrice :: (Num a, Ord a) => Vector a -> Vector a -> Vector a Source #

The Projection Preserving Marginality as described in Algorithm 21 of the validityAllocation paper, applied to a price vector.

Unraveling

data UnravelState b a Source #

Constructors

UnravelState 

Instances

(Show a, Show b) => Show (UnravelState b a) Source # 

unravelUnambiguous :: forall a b m. (Num a, Ord a, Show a, Eq b, Ord b, Show b, Monad m) => StateT (AllocationProblemOf b a) m () Source #

Algorithm 23 from the validityAllocation paper. Unravel all the unambiguous allocations in an allocation problem.

unravelUnambiguousL :: forall a b m. (Num a, Ord a, Show a, Eq b, Ord b, Show b, Monad m) => (String -> m ()) -> StateT (AllocationProblemOf b a) m () Source #

Flavor of unravelUnambiguous with monadic trace logging.

Priority-based allocation

allocatePriorityBased Source #

Arguments

:: (Ord prio, Eq b, Ord b, Show b, Monad m) 
=> (Good -> BidAgentID b -> prio)

Priority function

-> StateT (AllocationProblem b) m () 

Algorithm 24 from the validityAllocation paper: priority-based procedure to solve an allocation problem.

allocatePriorityBasedL Source #

Arguments

:: (Ord prio, Eq b, Ord b, Show b, Monad m) 
=> (String -> m ())

Trace logger

-> (Good -> BidAgentID b -> prio)

Priority function

-> StateT (AllocationProblem b) m () 

Flavor of allocatePriorityBased with monadic trace logging.

Running a full auction

Representing incoming auction data

data Auction b Source #

An auction, as provided by the user. Before the algorithms can process this, preprocessing as defined in Algorithm 1 is required, which is provided by prepareAP

Instances

Eq b => Eq (Auction b) Source # 

Methods

(==) :: Auction b -> Auction b -> Bool #

(/=) :: Auction b -> Auction b -> Bool #

Show b => Show (Auction b) Source # 

Methods

showsPrec :: Int -> Auction b -> ShowS #

show :: Auction b -> String #

showList :: [Auction b] -> ShowS #

ToJSONKey b => ToJSON (Auction b) Source # 

Methods

toJSON :: Auction b -> Value

toEncoding :: Auction b -> Encoding

toJSONList :: [Auction b] -> Value

toEncodingList :: [Auction b] -> Encoding

(Ord b, FromJSONKey b) => FromJSON (Auction b) Source # 

Methods

parseJSON :: Value -> Parser (Auction b)

parseJSONList :: Value -> Parser [Auction b]

auctionSupply :: forall b. Lens' (Auction b) Bundle Source #

auctionBids :: forall b b. Lens (Auction b) (Auction b) (Map b [IncomingBid]) (Map b [IncomingBid]) Source #

data IncomingBid Source #

A raw bid, as provided by the user.

Instances

Eq IncomingBid Source # 
Show IncomingBid Source # 
Generic IncomingBid Source # 

Associated Types

type Rep IncomingBid :: * -> * #

ToJSON IncomingBid Source # 

Methods

toJSON :: IncomingBid -> Value

toEncoding :: IncomingBid -> Encoding

toJSONList :: [IncomingBid] -> Value

toEncodingList :: [IncomingBid] -> Encoding

FromJSON IncomingBid Source # 

Methods

parseJSON :: Value -> Parser IncomingBid

parseJSONList :: Value -> Parser [IncomingBid]

ToRecord IncomingBid Source # 

Methods

toRecord :: IncomingBid -> Record

FromRecord IncomingBid Source # 

Methods

parseRecord :: Record -> Parser IncomingBid

type Rep IncomingBid Source # 
type Rep IncomingBid = D1 (MetaData "IncomingBid" "ProductMixAuction.DotBids" "product-mix-auction-0.1.0.0-inplace" False) (C1 (MetaCons "IncomingBid" PrefixI True) ((:*:) (S1 (MetaSel (Just Symbol "_incomingBidQuantity") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Units)) (S1 (MetaSel (Just Symbol "_incomingBidPrices") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PriceVector))))

Representing outgoing auction result data

data AuctionResult b Source #

Instances

Eq b => Eq (AuctionResult b) Source # 
Show b => Show (AuctionResult b) Source # 
(ToJSON b, ToJSONKey b, Eq b, Show b) => ToJSON (AuctionResult b) Source # 

Methods

toJSON :: AuctionResult b -> Value

toEncoding :: AuctionResult b -> Encoding

toJSONList :: [AuctionResult b] -> Value

toEncodingList :: [AuctionResult b] -> Encoding

Running an auction

runAuction :: forall b. (Show b, Ord b) => Auction b -> AuctionResult b Source #

Run a full auction, using the priority-based algorithm (Algorithm 24 in validityAllocation).

runAuctionM :: forall b m. (Show b, Ord b, Monad m) => (String -> m ()) -> Auction b -> m (AuctionResult b) Source #

Flavor of runAuction with monadic trace logging.

Converting to and from AllocationProblems

resultFromAP :: Ord b => PriceVector -> AllocationProblem b -> AuctionResult b Source #

Convert a solved allocation problem to an auction result. This covers the following:

  • Reverting reserve price normalization
  • Removing auctioneer endowments
  • Removing REJECT coordinates from all endowments, prices, and bundles
  • Collecting all remaining supply as well as supply allocated to the auctioneer into a single rejected bundle
  • Carrying over good labels from the original auction

prepareAP :: (Ord b, Show b, Monad m) => (String -> m ()) -> Auction b -> m (PriceVector, AllocationProblem b) Source #

Prepare an auction for processing, creating an allocation problem. This includes:

  • Adding a 0th element to every price and bundle (the REJECT good)
  • Applying reserve price normalization
  • Adding an auctioneer bidder and auctioneer bids
  • Finding an equilibrium price

prepareBids :: Ord b => Map b [IncomingBid] -> [DotBid b] Source #

Prepare a list of bids for processing.

prepareAgentBids :: b -> [IncomingBid] -> [DotBid b] Source #

Prepare a list of bids from one agent for processing.

prepareAgentBid :: b -> IncomingBid -> DotBid b Source #

Prepare one agent + bid pair for processing.

Generating random Auctions

genAuction Source #

Arguments

:: (Ord b, Eq b) 
=> Integer

Maximum weight per bid (1 for unit-bids only)

-> Integer

Maximum price for bids

-> Int

Number of goods in the auction / dimensionality

-> Int

The b parameter from the paper

-> [b]

Bidder names. List length implies number of bidders.

-> Gen (Auction b) 

Generate a valid auction with multiple bidders.