feat(encode): add cardinality constraint encodings
This commit is contained in:
1 parent
64876af98f
commit
3854d42178
1 file changed
+60
@@ -0,0 +1,60 @@
|
||||
module Sift.Encode.Cardinality
|
||||
( atLeastOne
|
||||
, atMostOne
|
||||
, exactlyOne
|
||||
, atMostK
|
||||
, atLeastK
|
||||
, exactlyK
|
||||
) where
|
||||
|
||||
import Sift.Types
|
||||
|
||||
atLeastOne :: [Lit] -> [Clause]
|
||||
atLeastOne lits = [lits]
|
||||
|
||||
atMostOne :: [Lit] -> [Clause]
|
||||
atMostOne lits =
|
||||
[ [neg a, neg b]
|
||||
| (a, rest) <- pairsFrom lits
|
||||
, b <- rest
|
||||
]
|
||||
|
||||
exactlyOne :: [Lit] -> [Clause]
|
||||
exactlyOne lits = atLeastOne lits ++ atMostOne lits
|
||||
|
||||
pairsFrom :: [a] -> [(a, [a])]
|
||||
pairsFrom [] = []
|
||||
pairsFrom (x : xs) = (x, xs) : pairsFrom xs
|
||||
|
||||
atMostK :: Int -> [Lit] -> Int -> ([Clause], Int)
|
||||
atMostK k lits freshStart
|
||||
| k <= 0 = (map (\l -> [neg l]) lits, freshStart)
|
||||
| n <= k = ([], freshStart)
|
||||
| otherwise = (concat (zipWith rowClauses [1 ..] lits), freshStart + n * k)
|
||||
where
|
||||
n = length lits
|
||||
reg i j = posLit (Var (freshStart + (i - 1) * k + (j - 1)))
|
||||
rowClauses i xi
|
||||
| i == 1 =
|
||||
[ [neg xi, reg 1 1] ]
|
||||
++ [ [neg (reg 1 j)] | j <- [2 .. k] ]
|
||||
| i == n =
|
||||
[ [neg xi, neg (reg (i - 1) k)] ]
|
||||
| otherwise =
|
||||
[ [neg xi, reg i 1]
|
||||
, [neg (reg (i - 1) 1), reg i 1] ]
|
||||
++ concat
|
||||
[ [ [neg xi, neg (reg (i - 1) (j - 1)), reg i j]
|
||||
, [neg (reg (i - 1) j), reg i j] ]
|
||||
| j <- [2 .. k] ]
|
||||
++ [ [neg xi, neg (reg (i - 1) k)] ]
|
||||
|
||||
atLeastK :: Int -> [Lit] -> Int -> ([Clause], Int)
|
||||
atLeastK k lits = atMostK (n - k) (map neg lits)
|
||||
where n = length lits
|
||||
|
||||
exactlyK :: Int -> [Lit] -> Int -> ([Clause], Int)
|
||||
exactlyK k lits freshStart =
|
||||
let (atMost, fresh1) = atMostK k lits freshStart
|
||||
(atLeast, fresh2) = atLeastK k lits fresh1
|
||||
in (atMost ++ atLeast, fresh2)
|
||||
Reference in new issue
Block a user