Merge branch 'master' into popl2012
[match/match.git] / program / ProposalMatcher.hs
CommitLineData
967c39ef 1module ProposalMatcher where
d7d9561e
MM
2import Data.Array.IArray
3import Data.Graph.Inductive.Graph
4import Data.Graph.Inductive.Tree
5import Data.List
578d7d98 6import Data.Either
d7d9561e 7
d3852a83 8import ArrayStuff
578d7d98 9import MonadStuff
05a6f0ed 10import PMInstance
bc14b3b3 11import PMConfig
8c5ee850
MM
12
13prefBoringness cfg p = if prefIsVeryBoring cfg p then 2
14 else if prefIsBoring cfg p then 1 else 0
56b565b1
MM
15expExpertness cfg x = if expIsExpert cfg x then 2
16 else if expIsKnowledgeable cfg x then 1 else 0
2e7d5426 17
5a07db44
MM
18data REdge = REdge {
19 reIdx :: Int,
20 reCap :: Int,
21 reCost :: Wt
22}
23
24instance Show REdge where
25 show (REdge idx cap cost) = "#" ++ (show idx) ++ ": "
26 ++ (show cap) ++ " @ " ++ (show cost)
27
28data ReductionResult = ReductionResult {
29 rrGraph :: Gr () REdge,
30 rrSource :: Node,
31 rrSink :: Node,
32 rrEIdxBounds :: (Int, Int),
33 rrEDIdx :: (Int, Int) -> Int
34}
35
36-- Hack: show as much of the reduction result as we easily can
37data RR1 = RR1 (Gr () REdge) Node Node (Int, Int) deriving Show
38instance Show ReductionResult where
39 show (ReductionResult g so si eib _) = show (RR1 g so si eib)
40
41indexEdges :: Int -> [(Int, Int, REdge)] -> (Int, [(Int, Int, REdge)])
42indexEdges i [] = (i, [])
43indexEdges i ((v1, v2, re):es) =
44 let (imax, ies) = indexEdges (i+1) es in
45 (imax, (v1, v2, re{ reIdx = i }) : ies)
46
d3852a83
MM
47implies :: Bool -> Bool -> Bool
48x `implies` y = (not x) || y
49
05a6f0ed 50doReduction :: PMConfig -> PMInstance -> ReductionResult
578d7d98 51doReduction cfg (PMInstance numRvrs numProps rloadA prefA expA fixA pnrA) =
d7d9561e 52 let
d3852a83
MM
53 -- Need to figure out who is PC/ERC
54 isPC = (funcArray (0, numRvrs-1) (\i -> (rloadA ! i) == 1)) :: Array Int Bool
55 isPCPaper = (funcArray (0, numProps-1) (\j -> all (\i -> (isPC ! i) `implies` (prefIsConflict cfg $ (prefA ! (i, j)))) [0 .. numRvrs - 1])) :: Array Int Bool
d7d9561e
MM
56 source = 0
57 sink = 1
2e7d5426 58 rvrNode i boringness = 2 + 3*i + boringness
d3852a83
MM
59 -- We will waste a lot of nodes. Who cares, no one will visit them.
60 propNode j k = 2 + 3*numRvrs + 7*j + k
61 numNodes = 2 + 3*numRvrs + 7*numProps
5a07db44 62 edIdx (i, j) = i*numProps + j
d7d9561e
MM
63 in
64 let
578d7d98 65 totalReviews = sum $ elems pnrA -- (reviewsEachProposal cfg) * numProps
967c39ef 66 totalRelativeLoad = foldl (+) 0 (map (rloadA !) [0 .. numRvrs - 1])
d3852a83
MM
67 -- floor goes best with loadTolerance 2
68 targetLoad i = floor (widenInteger totalReviews * (rloadA ! i) / totalRelativeLoad) - 1
17e0995d 69 -- Edge groups A through H are indicated in the figure in the paper.
2e7d5426 70 edgesABC = do
d7d9561e 71 i <- [0 .. numRvrs - 1]
2e7d5426 72 let tl = targetLoad i
578d7d98 73 let lt = if isPC ! i then loadTolerance cfg else ercLoadTolerance cfg
5a07db44
MM
74 let freeEdgeA = (source, rvrNode i 0, REdge undefined tl 0)
75 let nonfreeEdgesA = do
578d7d98
MM
76 l <- [tl .. tl + lt - 1]
77 let costA = marginalLoadCost cfg ((widenInteger (l - tl) + 1/2) / widenInteger lt)
d3852a83 78 return (source, rvrNode i 0, REdge undefined 1 costA)
5a07db44 79 let edgesBC = do
578d7d98 80 l <- [0 .. tl + lt - 1]
96fe6497 81 let costB = marginalBoringCost cfg ((widenInteger l + 1/2) / widenInteger tl)
5a07db44 82 let edgeB = (rvrNode i 0, rvrNode i 1, REdge undefined 1 costB)
96fe6497 83 let costC = marginalVeryBoringCost cfg ((widenInteger l + 1/2) / widenInteger tl)
5a07db44
MM
84 let edgeC = (rvrNode i 1, rvrNode i 2, REdge undefined 1 costC)
85 [edgeB, edgeC]
86 [freeEdgeA] ++ nonfreeEdgesA ++ edgesBC
578d7d98 87 edgesDFix = do
d7d9561e
MM
88 i <- [0 .. numRvrs - 1]
89 j <- [0 .. numProps - 1]
967c39ef 90 let pref = prefA ! (i, j)
56b565b1 91 let xp = expA ! (i, j)
fd0d2377
MM
92 -- We must generate an edge even if there is a conflict
93 -- of interest; otherwise we'll fail to read its flow
94 -- value in doMatching.
d3852a83 95 let xp_ = expExpertness cfg xp
578d7d98 96 let pn = propNode j $ if (isPC ! i)
d3852a83
MM
97 then xp_ + 3 -- Can assume it is a PC paper, otherwise it would conflict anyway.
98 else xp_
578d7d98
MM
99 let rn = rvrNode i (prefBoringness cfg pref)
100 if fixA ! (i, j)
101 -- Max flow will emulate one unit of flow through the edge,
102 -- at a cost of increasing the total flow value by 1.
103 then [Right (rn, sink, REdge undefined 1 0),
104 Right (source, pn, REdge undefined 1 0)]
105 else [Left (rn, pn, REdge (edIdx (i, j))
8c5ee850
MM
106 (if prefIsConflict cfg pref then 0 else 1)
107 (assignmentCost cfg pref))]
578d7d98
MM
108 edgesD = lefts edgesDFix
109 edgesFix = rights edgesDFix
5a07db44 110 edgesEFGH = do
d7d9561e 111 j <- [0 .. numProps - 1]
d3852a83 112 -- This is now different...
578d7d98 113 let numReviews = pnrA ! j
d3852a83
MM
114 if isPCPaper ! j
115 then do -- Mostly traditional.
116 -- Expert bonus
117 let edgeFFirst = (propNode j 2, propNode j 1, REdge undefined 1 (-(expertBonus cfg)))
578d7d98 118 let edgeFRest = (propNode j 2, propNode j 1, REdge undefined (numReviews - 1) 0)
d3852a83
MM
119 -- Second kowledgeable bonus
120 let edgeGFirst = (propNode j 1, propNode j 0, REdge undefined 1 (-(knowledgeableBonus cfg)))
578d7d98 121 let edgeGRest = (propNode j 1, propNode j 0, REdge undefined (numReviews - 2) 0)
d3852a83
MM
122 -- Require one knowledgeable
123 let edgeH1 = (propNode j 1, sink, REdge undefined 1 0)
578d7d98 124 let edgeH = (propNode j 0, sink, REdge undefined (numReviews - 1) 0)
d3852a83
MM
125 [edgeFFirst, edgeFRest, edgeGFirst, edgeGRest, edgeH1, edgeH]
126 else do -- New gadget; man, a lot of edges
578d7d98
MM
127 let numPCReviews = pcReviewsEachProposal cfg
128 if numReviews < numPCReviews then fail "numReviews for paper < numPCReviews" else nop
d3852a83 129 -- Structure to distribute knowledgeable PC members
578d7d98
MM
130 let edgesP = [(propNode j k, propNode j 6, REdge undefined numPCReviews 0) | k <- [4 .. 5]]
131 let edgesR = [(propNode j k, propNode j (k - 3), REdge undefined (numReviews - numPCReviews) 0) | k <- [4 .. 5]]
d3852a83 132 -- "Designated knowledgeable" with expert bonus
578d7d98
MM
133 let edgeF = (propNode j 2, propNode j 1, REdge undefined (numReviews - numPCReviews) (-(expertBonus cfg)))
134 let edgeH1 = (propNode j 1, sink, REdge undefined (numReviews - numPCReviews) 0)
d3852a83
MM
135 -- "Designated PC" with knowledgeable bonus
136 let edgeGFirst = (propNode j 6, propNode j 3, REdge undefined 1 (-(knowledgeableBonus cfg)))
59c94dee
MM
137 let edgeGRest = (propNode j 6, propNode j 3, REdge undefined (numPCReviews - 1) 0)
138 let edgeH = (propNode j 3, sink, REdge undefined (numPCReviews) 0)
d3852a83 139 edgesP ++ edgesR ++ [edgeF, edgeH1, edgeGFirst, edgeGRest, edgeH]
2e7d5426 140 theNodes = [(x, ()) | x <- [0 .. numNodes - 1]]
5a07db44 141 -- Index the non-D edges
578d7d98 142 unindexedEdges = edgesABC ++ edgesFix ++ edgesEFGH
5a07db44
MM
143 (imax, reindexedEdges) = indexEdges (numRvrs*numProps) unindexedEdges
144 theEdges = edgesD ++ reindexedEdges
d7d9561e 145 in
5a07db44 146 ReductionResult (mkGraph theNodes theEdges) source sink (0, imax-1) edIdx
d7d9561e 147
d7d9561e 148-- Returns a list of reviews as ordered pairs (reviewer#, proposal#).
05a6f0ed 149doMatching :: PMConfig -> PMInstance -> PMatching
578d7d98 150doMatching cfg inst@(PMInstance numRvrs numProps _ _ _ fixA _) =
8c5ee850
MM
151 let ReductionResult graph source sink idxBounds edIdx = doReduction cfg inst in
152 let flowArray = minCostFlow cfg idxBounds reIdx reCap reCost graph (source, sink) in
d7d9561e
MM
153 let pairs = do
154 i <- [0 .. numRvrs - 1]
5a07db44 155 j <- [0 .. numProps - 1]
578d7d98 156 if fixA ! (i, j) || flowArray ! edIdx (i, j) == 1
5a07db44 157 then [(i, j)]
2e7d5426
MM
158 else []
159 in
56b565b1 160 PMatching (sort pairs) -- for prettiness