• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

msakai / toysolver / 463

24 Aug 2024 02:14PM UTC coverage: 71.506% (-0.007%) from 71.513%
463

push

github

web-flow
Merge pull request #112 from msakai/cache-key-cabal-hash

Include hash of cabal file in the key for actions/cache

10008 of 13996 relevant lines covered (71.51%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.4
/src/ToySolver/SAT/Solver/CDCL.hs
1
{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
2
{-# OPTIONS_HADDOCK show-extensions #-}
3
{-# LANGUAGE BangPatterns #-}
4
{-# LANGUAGE CPP #-}
5
{-# LANGUAGE DeriveDataTypeable #-}
6
{-# LANGUAGE InstanceSigs #-}
7
{-# LANGUAGE MultiParamTypeClasses #-}
8
{-# LANGUAGE RecursiveDo #-}
9
{-# LANGUAGE ScopedTypeVariables #-}
10
#ifdef __GLASGOW_HASKELL__
11
{-# LANGUAGE MagicHash #-}
12
{-# LANGUAGE UnboxedTuples #-}
13
#endif
14
#include "MachDeps.h"
15
-----------------------------------------------------------------------------
16
-- |
17
-- Module      :  ToySolver.SAT.Solver.CDCL
18
-- Copyright   :  (c) Masahiro Sakai 2012-2014
19
-- License     :  BSD-style
20
--
21
-- Maintainer  :  masahiro.sakai@gmail.com
22
-- Stability   :  provisional
23
-- Portability :  non-portable
24
--
25
-- A CDCL SAT solver.
26
--
27
-- It follows the design of MiniSat and SAT4J.
28
--
29
-- See also:
30
--
31
-- * <http://hackage.haskell.org/package/funsat>
32
--
33
-- * <http://hackage.haskell.org/package/incremental-sat-solver>
34
--
35
-----------------------------------------------------------------------------
36
module ToySolver.SAT.Solver.CDCL
37
  (
38
  -- * The @Solver@ type
39
    Solver
40
  , newSolver
41
  , newSolverWithConfig
42

43
  -- * Basic data structures
44
  , Var
45
  , Lit
46
  , literal
47
  , litNot
48
  , litVar
49
  , litPolarity
50
  , evalLit
51

52
  -- * Problem specification
53
  , newVar
54
  , newVars
55
  , newVars_
56
  , resizeVarCapacity
57
  -- ** Clauses
58
  , AddClause (..)
59
  , Clause
60
  , evalClause
61
  , PackedClause
62
  , packClause
63
  , unpackClause
64
  -- ** Cardinality constraints
65
  , AddCardinality (..)
66
  , AtLeast
67
  , Exactly
68
  , evalAtLeast
69
  , evalExactly
70

71
  -- ** (Linear) pseudo-boolean constraints
72
  , AddPBLin (..)
73
  , PBLinTerm
74
  , PBLinSum
75
  , PBLinAtLeast
76
  , PBLinExactly
77
  , evalPBLinSum
78
  , evalPBLinAtLeast
79
  , evalPBLinExactly
80
  -- ** XOR clauses
81
  , AddXORClause (..)
82
  , XORClause
83
  , evalXORClause
84
  -- ** Theory
85
  , setTheory
86

87
  -- * Solving
88
  , solve
89
  , solveWith
90
  , BudgetExceeded (..)
91
  , cancel
92
  , Canceled (..)
93

94
  -- * Extract results
95
  , IModel (..)
96
  , Model
97
  , getModel
98
  , getFailedAssumptions
99
  , getAssumptionsImplications
100

101
  -- * Solver configulation
102
  , module ToySolver.SAT.Solver.CDCL.Config
103
  , getConfig
104
  , setConfig
105
  , modifyConfig
106
  , setVarPolarity
107
  , setRandomGen
108
  , getRandomGen
109
  , setConfBudget
110

111
  -- * Callbacks
112
  , setLogger
113
  , clearLogger
114
  , setTerminateCallback
115
  , clearTerminateCallback
116
  , setLearnCallback
117
  , clearLearnCallback
118

119
  -- * Read state
120
  , getNVars
121
  , getNConstraints
122
  , getNLearntConstraints
123
  , getVarFixed
124
  , getLitFixed
125
  , getFixedLiterals
126

127
  -- * Internal API
128
  , varBumpActivity
129
  , varDecayActivity
130
  ) where
131

132
import Prelude hiding (log)
133
import Control.Loop
134
import Control.Monad
135
import Control.Monad.IO.Class
136
import Control.Monad.Trans
137
import Control.Monad.Trans.Except
138
import Control.Exception
139
import Data.Array.IO
140
import Data.Array.Unsafe (unsafeFreeze)
141
import Data.Array.Base (unsafeRead, unsafeWrite)
142
import Data.Bits (xor) -- for defining 'combine' function
143
import Data.Coerce
144
import Data.Default.Class
145
import Data.Either
146
import Data.Function (on)
147
import Data.Hashable
148
import Data.HashSet (HashSet)
149
import qualified Data.HashSet as HashSet
150
import Data.IORef
151
import Data.Int
152
import Data.List
153
import Data.Maybe
154
import Data.Ord
155
import qualified Data.IntMap.Strict as IM
156
import qualified Data.IntSet as IS
157
import qualified Data.Set as Set
158
import ToySolver.Internal.Data.IOURef
159
import qualified ToySolver.Internal.Data.IndexedPriorityQueue as PQ
160
import qualified ToySolver.Internal.Data.Vec as Vec
161
import Data.Typeable
162
import System.Clock
163
import qualified System.Random.MWC as Rand
164
import Text.Printf
165

166
#ifdef __GLASGOW_HASKELL__
167
import GHC.Types (IO (..))
168
import GHC.Exts hiding (Constraint)
169
#endif
170

171
import ToySolver.Data.LBool
172
import ToySolver.SAT.Solver.CDCL.Config
173
import ToySolver.SAT.Types
174
import ToySolver.SAT.TheorySolver
175
import ToySolver.Internal.Util (revMapM)
176

177
{--------------------------------------------------------------------
178
  LitArray
179
--------------------------------------------------------------------}
180

181
newtype LitArray = LitArray (IOUArray Int PackedLit) deriving (Eq)
×
182

183
newLitArray :: [Lit] -> IO LitArray
184
newLitArray lits = do
1✔
185
  let size = length lits
1✔
186
  liftM LitArray $ newListArray (0, size-1) (map packLit lits)
1✔
187

188
readLitArray :: LitArray -> Int -> IO Lit
189
#if EXTRA_BOUNDS_CHECKING
190
readLitArray (LitArray a) i = liftM unpackLit $ readArray a i
191
#else
192
readLitArray (LitArray a) i = liftM unpackLit $ unsafeRead a i
1✔
193
#endif
194

195
writeLitArray :: LitArray -> Int -> Lit -> IO ()
196
#if EXTRA_BOUNDS_CHECKING
197
writeLitArray (LitArray a) i lit = writeArray a i (packLit lit)
198
#else
199
writeLitArray (LitArray a) i lit = unsafeWrite a i (packLit lit)
1✔
200
#endif
201

202
getLits :: LitArray -> IO [Lit]
203
getLits (LitArray a) = liftM (map unpackLit) $ getElems a
1✔
204

205
getLitArraySize :: LitArray -> IO Int
206
getLitArraySize (LitArray a) = do
1✔
207
  (lb,ub) <- getBounds a
1✔
208
  assert (lb == 0) $ return ()
×
209
  return $! ub-lb+1
1✔
210

211
{--------------------------------------------------------------------
212
  internal data structures
213
--------------------------------------------------------------------}
214

215
type Level = Int
216

217
levelRoot :: Level
218
levelRoot = 0
1✔
219

220
litIndex :: Lit -> Int
221
litIndex l = 2 * (litVar l - 1) + (if litPolarity l then 1 else 0)
1✔
222

223
{-# INLINE varValue #-}
224
varValue :: Solver -> Var -> IO LBool
225
varValue solver v = liftM coerce $ Vec.unsafeRead (svVarValue solver) (v - 1)
1✔
226

227
{-# INLINE litValue #-}
228
litValue :: Solver -> Lit -> IO LBool
229
litValue solver !l = do
1✔
230
  -- litVar による heap allocation を避けるために、
231
  -- litPolarityによる分岐後にvarValueを呼ぶ。
232
  if litPolarity l then
1✔
233
    varValue solver l
1✔
234
  else do
1✔
235
    m <- varValue solver (negate l)
1✔
236
    return $! lnot m
1✔
237

238
getVarFixed :: Solver -> Var -> IO LBool
239
getVarFixed solver !v = do
1✔
240
  lv <- Vec.unsafeRead (svVarLevel solver) (v - 1)
1✔
241
  if lv == levelRoot then
1✔
242
    varValue solver v
1✔
243
  else
244
    return lUndef
1✔
245

246
getLitFixed :: Solver -> Lit -> IO LBool
247
getLitFixed solver !l = do
1✔
248
  -- litVar による heap allocation を避けるために、
249
  -- litPolarityによる分岐後にvarGetFixedを呼ぶ。
250
  if litPolarity l then
1✔
251
    getVarFixed solver l
1✔
252
  else do
1✔
253
    m <- getVarFixed solver (negate l)
1✔
254
    return $! lnot m
1✔
255

256
getNFixed :: Solver -> IO Int
257
getNFixed solver = do
1✔
258
  lv <- getDecisionLevel solver
1✔
259
  if lv == levelRoot then
×
260
    Vec.getSize (svTrail solver)
1✔
261
  else
262
    Vec.unsafeRead (svTrailLimit solver) 0
×
263

264
-- | it returns a set of literals that are fixed without any assumptions.
265
getFixedLiterals :: Solver -> IO [Lit]
266
getFixedLiterals solver = do
×
267
  n <- getNFixed solver
×
268
  revMapM (Vec.unsafeRead (svTrail solver)) [0..n-1]
×
269

270
varLevel :: Solver -> Var -> IO Level
271
varLevel solver !v = do
1✔
272
  val <- varValue solver v
1✔
273
  when (val == lUndef) $ error ("ToySolver.SAT.varLevel: unassigned var " ++ show v)
×
274
  Vec.unsafeRead (svVarLevel solver) (v - 1)
1✔
275

276
litLevel :: Solver -> Lit -> IO Level
277
litLevel solver l = varLevel solver (litVar l)
1✔
278

279
varReason :: Solver -> Var -> IO (Maybe SomeConstraintHandler)
280
varReason solver !v = do
1✔
281
  val <- varValue solver v
1✔
282
  when (val == lUndef) $ error ("ToySolver.SAT.varReason: unassigned var " ++ show v)
×
283
  Vec.unsafeRead (svVarReason solver) (v - 1)
1✔
284

285
varAssignNo :: Solver -> Var -> IO Int
286
varAssignNo solver !v = do
1✔
287
  val <- varValue solver v
1✔
288
  when (val == lUndef) $ error ("ToySolver.SAT.varAssignNo: unassigned var " ++ show v)
×
289
  Vec.unsafeRead (svVarTrailIndex solver) (v - 1)
1✔
290

291
-- | Solver instance
292
data Solver
293
  = Solver
294
  { svOk           :: !(IORef Bool)
1✔
295

296
  , svVarQueue     :: !PQ.PriorityQueue
1✔
297
  , svTrail        :: !(Vec.UVec Lit)
1✔
298
  , svTrailLimit   :: !(Vec.UVec Lit)
1✔
299
  , svTrailNPropagated :: !(IOURef Int)
1✔
300

301
  -- variable information
302
  , svVarValue      :: !(Vec.UVec Int8) -- should be 'Vec.UVec LBool' but it's difficult to define MArray instance
1✔
303
  , svVarPolarity   :: !(Vec.UVec Bool)
1✔
304
  , svVarActivity   :: !(Vec.UVec VarActivity)
1✔
305
  , svVarTrailIndex :: !(Vec.UVec Int)
1✔
306
  , svVarLevel      :: !(Vec.UVec Int)
1✔
307
  -- | will be invoked once when the variable is assigned
308
  , svVarWatches      :: !(Vec.Vec [SomeConstraintHandler])
1✔
309
  , svVarOnUnassigned :: !(Vec.Vec [SomeConstraintHandler])
1✔
310
  , svVarReason       :: !(Vec.Vec (Maybe SomeConstraintHandler))
1✔
311
  -- | exponential moving average estimate
312
  , svVarEMAScaled    :: !(Vec.UVec Double)
1✔
313
  -- | When v was last assigned
314
  , svVarWhenAssigned :: !(Vec.UVec Int)
1✔
315
  -- | The number of learnt clauses v participated in generating since Assigned.
316
  , svVarParticipated :: !(Vec.UVec Int)
1✔
317
  -- | The number of learnt clauses v reasoned in generating since Assigned.
318
  , svVarReasoned     :: !(Vec.UVec Int)
1✔
319

320
  -- | will be invoked when this literal is falsified
321
  , svLitWatches   :: !(Vec.Vec [SomeConstraintHandler])
1✔
322
  , svLitOccurList :: !(Vec.Vec (HashSet SomeConstraintHandler))
1✔
323

324
  , svConstrDB     :: !(IORef [SomeConstraintHandler])
1✔
325
  , svLearntDB     :: !(IORef (Int,[SomeConstraintHandler]))
1✔
326

327
  -- Theory
328
  , svTheorySolver  :: !(IORef (Maybe TheorySolver))
1✔
329
  , svTheoryChecked :: !(IOURef Int)
1✔
330

331
  -- Result
332
  , svModel        :: !(IORef (Maybe Model))
1✔
333
  , svFailedAssumptions :: !(IORef LitSet)
1✔
334
  , svAssumptionsImplications :: !(IORef LitSet)
1✔
335

336
  -- Statistics
337
  , svNDecision    :: !(IOURef Int)
1✔
338
  , svNRandomDecision :: !(IOURef Int)
1✔
339
  , svNConflict    :: !(IOURef Int)
1✔
340
  , svNRestart     :: !(IOURef Int)
1✔
341
  , svNLearntGC    :: !(IOURef Int)
1✔
342
  , svNRemovedConstr :: !(IOURef Int)
1✔
343

344
  -- Configulation
345
  , svConfig :: !(IORef Config)
1✔
346
  , svRandomGen  :: !(IORef Rand.GenIO)
1✔
347
  , svConfBudget :: !(IOURef Int)
1✔
348
  , svTerminateCallback :: !(IORef (Maybe (IO Bool)))
1✔
349
  , svLearnCallback :: !(IORef (Maybe (Clause -> IO ())))
1✔
350

351
  -- Logging
352
  , svLogger :: !(IORef (Maybe (String -> IO ())))
1✔
353
  , svStartWC    :: !(IORef TimeSpec)
1✔
354
  , svLastStatWC :: !(IORef TimeSpec)
1✔
355

356
  -- Working spaces
357
  , svCanceled        :: !(IORef Bool)
1✔
358
  , svAssumptions     :: !(Vec.UVec Lit)
1✔
359
  , svLearntLim       :: !(IORef Int)
1✔
360
  , svLearntLimAdjCnt :: !(IORef Int)
1✔
361
  , svLearntLimSeq    :: !(IORef [(Int,Int)])
1✔
362
  , svSeen :: !(Vec.UVec Bool)
1✔
363
  , svPBLearnt :: !(IORef (Maybe PBLinAtLeast))
1✔
364

365
  -- | Amount to bump next variable with.
366
  , svVarInc       :: !(IOURef Double)
1✔
367

368
  -- | Amount to bump next constraint with.
369
  , svConstrInc    :: !(IOURef Double)
1✔
370

371
  -- ERWA / LRB
372

373
  -- | step-size parameter α
374
  , svERWAStepSize :: !(IOURef Double)
1✔
375
  , svEMAScale :: !(IOURef Double)
1✔
376
  , svLearntCounter :: !(IOURef Int)
1✔
377
  }
378

379
markBad :: Solver -> IO ()
380
markBad solver = do
1✔
381
  writeIORef (svOk solver) False
1✔
382
  bcpClear solver
1✔
383

384
bcpDequeue :: Solver -> IO (Maybe Lit)
385
bcpDequeue solver = do
1✔
386
  n <- Vec.getSize (svTrail solver)
1✔
387
  m <- readIOURef (svTrailNPropagated solver)
1✔
388
  if m==n then
1✔
389
    return Nothing
1✔
390
  else do
1✔
391
    -- m < n
392
    lit <- Vec.unsafeRead (svTrail solver) m
1✔
393
    modifyIOURef (svTrailNPropagated solver) (+1)
1✔
394
    return (Just lit)
1✔
395

396
bcpIsEmpty :: Solver -> IO Bool
397
bcpIsEmpty solver = do
1✔
398
  p <- readIOURef (svTrailNPropagated solver)
1✔
399
  n <- Vec.getSize (svTrail solver)
1✔
400
  return $! n == p
1✔
401

402
bcpCheckEmpty :: Solver -> IO ()
403
bcpCheckEmpty solver = do
1✔
404
  empty <- bcpIsEmpty solver
1✔
405
  unless empty $
1✔
406
    error "BUG: BCP Queue should be empty at this point"
×
407

408
bcpClear :: Solver -> IO ()
409
bcpClear solver = do
1✔
410
  m <- Vec.getSize (svTrail solver)
1✔
411
  writeIOURef (svTrailNPropagated solver) m
1✔
412

413
assignBy :: Solver -> Lit -> SomeConstraintHandler -> IO Bool
414
assignBy solver lit c = do
1✔
415
  lv <- getDecisionLevel solver
1✔
416
  let !c2 = if lv == levelRoot
1✔
417
            then Nothing
1✔
418
            else Just c
1✔
419
  assign_ solver lit c2
1✔
420

421
assign :: Solver -> Lit -> IO Bool
422
assign solver lit = assign_ solver lit Nothing
1✔
423

424
assign_ :: Solver -> Lit -> Maybe SomeConstraintHandler -> IO Bool
425
assign_ solver !lit reason = assert (validLit lit) $ do
×
426
  let val = liftBool (litPolarity lit)
1✔
427

428
  val0 <- varValue solver (litVar lit)
1✔
429
  if val0 /= lUndef then do
1✔
430
    return $ val == val0
1✔
431
  else do
1✔
432
    idx <- Vec.getSize (svTrail solver)
1✔
433
    lv <- getDecisionLevel solver
1✔
434

435
    Vec.unsafeWrite (svVarValue solver) (litVar lit - 1) (coerce val)
1✔
436
    Vec.unsafeWrite (svVarTrailIndex solver) (litVar lit - 1) idx
1✔
437
    Vec.unsafeWrite (svVarLevel solver) (litVar lit - 1) lv
1✔
438
    Vec.unsafeWrite (svVarReason solver) (litVar lit - 1) reason
1✔
439
    Vec.unsafeWrite (svVarWhenAssigned solver) (litVar lit - 1) =<< readIOURef (svLearntCounter solver)
1✔
440
    Vec.unsafeWrite (svVarParticipated solver) (litVar lit - 1) 0
1✔
441
    Vec.unsafeWrite (svVarReasoned solver) (litVar lit - 1) 0
1✔
442

443
    Vec.push (svTrail solver) lit
1✔
444

445
    when debugMode $ logIO solver $ do
×
446
      let r = case reason of
×
447
                Nothing -> ""
×
448
                Just _ -> " by propagation"
×
449
      return $ printf "assign(level=%d): %d%s" lv lit r
×
450

451
    return True
1✔
452

453
unassign :: Solver -> Var -> IO ()
454
unassign solver !v = assert (validVar v) $ do
×
455
  val <- varValue solver v
1✔
456
  when (val == lUndef) $ error "unassign: should not happen"
×
457

458
  flag <- configEnablePhaseSaving <$> getConfig solver
1✔
459
  when flag $ Vec.unsafeWrite (svVarPolarity solver) (v - 1) $! fromJust (unliftBool val)
1✔
460

461
  Vec.unsafeWrite (svVarValue solver) (v - 1) (coerce lUndef)
1✔
462
  Vec.unsafeWrite (svVarTrailIndex solver) (v - 1) maxBound
1✔
463
  Vec.unsafeWrite (svVarLevel solver) (v - 1) maxBound
1✔
464
  Vec.unsafeWrite (svVarReason solver) (v - 1) Nothing
×
465

466
  -- ERWA / LRB computation
467
  interval <- do
1✔
468
    t2 <- readIOURef (svLearntCounter solver)
1✔
469
    t1 <- Vec.unsafeRead (svVarWhenAssigned solver) (v - 1)
1✔
470
    return (t2 - t1)
1✔
471
  -- Interval = 0 is possible due to restarts.
472
  when (interval > 0) $ do
1✔
473
    participated <- Vec.unsafeRead (svVarParticipated solver) (v - 1)
1✔
474
    reasoned <- Vec.unsafeRead (svVarReasoned solver) (v - 1)
1✔
475
    alpha <- readIOURef (svERWAStepSize solver)
1✔
476
    let learningRate = fromIntegral participated / fromIntegral interval
1✔
477
        reasonSideRate = fromIntegral reasoned / fromIntegral interval
1✔
478
    scale <- readIOURef (svEMAScale solver)
1✔
479
    -- ema := (1 - α)ema + α*r
480
    Vec.unsafeModify (svVarEMAScaled solver) (v - 1) (\orig -> (1 - alpha) * orig + alpha * scale * (learningRate + reasonSideRate))
1✔
481
    -- If v is assigned by random decision, it's possible that v is still in the queue.
482
    PQ.update (svVarQueue solver) v
1✔
483

484
  let !l = if val == lTrue then v else -v
1✔
485
  cs <- Vec.unsafeRead (svVarOnUnassigned solver) (v - 1)
1✔
486
  Vec.unsafeWrite (svVarOnUnassigned solver) (v - 1) []
1✔
487
  forM_ cs $ \c ->
1✔
488
    constrOnUnassigned solver c c l
1✔
489

490
  PQ.enqueue (svVarQueue solver) v
1✔
491

492
addOnUnassigned :: Solver -> SomeConstraintHandler -> Lit -> IO ()
493
addOnUnassigned solver constr !l = do
1✔
494
  val <- varValue solver (litVar l)
1✔
495
  when (val == lUndef) $ error "addOnUnassigned: should not happen"
×
496
  Vec.unsafeModify (svVarOnUnassigned solver) (litVar l - 1) (constr :)
1✔
497

498
-- | Register the constraint to be notified when the literal becames false.
499
watchLit :: Solver -> Lit -> SomeConstraintHandler -> IO ()
500
watchLit solver !lit c = Vec.unsafeModify (svLitWatches solver) (litIndex lit) (c : )
1✔
501

502
-- | Register the constraint to be notified when the variable is assigned.
503
watchVar :: Solver -> Var -> SomeConstraintHandler -> IO ()
504
watchVar solver !var c = Vec.unsafeModify (svVarWatches solver) (var - 1) (c :)
1✔
505

506
unwatchLit :: Solver -> Lit -> SomeConstraintHandler -> IO ()
507
unwatchLit solver !lit c = Vec.unsafeModify (svLitWatches solver) (litIndex lit) (delete c)
1✔
508

509
unwatchVar :: Solver -> Lit -> SomeConstraintHandler -> IO ()
510
unwatchVar solver !var c = Vec.unsafeModify (svVarWatches solver) (var - 1) (delete c)
×
511

512
addToDB :: ConstraintHandler c => Solver -> c -> IO ()
513
addToDB solver c = do
1✔
514
  let c2 = toConstraintHandler c
1✔
515
  modifyIORef (svConstrDB solver) (c2 : )
1✔
516
  when debugMode $ logIO solver $ do
×
517
    str <- showConstraintHandler c
×
518
    return $ printf "constraint %s is added" str
×
519

520
  b <- isPBRepresentable c
1✔
521
  when b $ do
1✔
522
    (lhs,_) <- toPBLinAtLeast c
1✔
523
    forM_ lhs $ \(_,lit) -> do
1✔
524
       Vec.unsafeModify (svLitOccurList solver) (litIndex lit) (HashSet.insert c2)
1✔
525

526
addToLearntDB :: ConstraintHandler c => Solver -> c -> IO ()
527
addToLearntDB solver c = do
1✔
528
  modifyIORef (svLearntDB solver) $ \(n,xs) -> (n+1, toConstraintHandler c : xs)
1✔
529
  when debugMode $ logIO solver $ do
×
530
    str <- showConstraintHandler c
×
531
    return $ printf "constraint %s is added" str
×
532

533
reduceDB :: Solver -> IO ()
534
reduceDB solver = do
1✔
535
  (_,cs) <- readIORef (svLearntDB solver)
1✔
536

537
  xs <- forM cs $ \c -> do
1✔
538
    p <- constrIsProtected solver c
×
539
    w <- constrWeight solver c
×
540
    actval <- constrReadActivity c
1✔
541
    return (c, (p, w*actval))
1✔
542

543
  -- Note that False <= True
544
  let ys = sortBy (comparing snd) xs
1✔
545
      (zs,ws) = splitAt (length ys `div` 2) ys
1✔
546

547
  let loop [] ret = return ret
1✔
548
      loop ((c,(isShort,_)) : rest) ret = do
1✔
549
        flag <- if isShort
×
550
                then return True
×
551
                else isLocked solver c
1✔
552
        if flag then
1✔
553
          loop rest (c:ret)
1✔
554
        else do
1✔
555
          detach solver c
1✔
556
          loop rest ret
1✔
557
  zs2 <- loop zs []
1✔
558

559
  let cs2 = zs2 ++ map fst ws
1✔
560
      n2 = length cs2
1✔
561

562
  -- log solver $ printf "learnt constraints deletion: %d -> %d" n n2
563
  writeIORef (svLearntDB solver) (n2,cs2)
1✔
564

565
type VarActivity = Double
566

567
varActivity :: Solver -> Var -> IO VarActivity
568
varActivity solver v = Vec.unsafeRead (svVarActivity solver) (v - 1)
1✔
569

570
varDecayActivity :: Solver -> IO ()
571
varDecayActivity solver = do
1✔
572
  d <- configVarDecay <$> getConfig solver
1✔
573
  modifyIOURef (svVarInc solver) (d*)
1✔
574

575
varBumpActivity :: Solver -> Var -> IO ()
576
varBumpActivity solver !v = do
1✔
577
  inc <- readIOURef (svVarInc solver)
1✔
578
  Vec.unsafeModify (svVarActivity solver) (v - 1) (+inc)
1✔
579
  conf <- getConfig solver
1✔
580
  when (configBranchingStrategy conf == BranchingVSIDS) $ do
1✔
581
    PQ.update (svVarQueue solver) v
1✔
582
  aval <- Vec.unsafeRead (svVarActivity solver) (v - 1)
1✔
583
  when (aval > 1e20) $
1✔
584
    -- Rescale
585
    varRescaleAllActivity solver
×
586

587
varRescaleAllActivity :: Solver -> IO ()
588
varRescaleAllActivity solver = do
×
589
  let a = svVarActivity solver
×
590
  n <- getNVars solver
×
591
  forLoop 0 (<n) (+1) $ \i ->
×
592
    Vec.unsafeModify a i (* 1e-20)
×
593
  modifyIOURef (svVarInc solver) (* 1e-20)
×
594

595
varEMAScaled :: Solver -> Var -> IO Double
596
varEMAScaled solver v = Vec.unsafeRead (svVarEMAScaled solver) (v - 1)
1✔
597

598
varIncrementParticipated :: Solver -> Var -> IO ()
599
varIncrementParticipated solver v = Vec.unsafeModify (svVarParticipated solver) (v - 1) (+1)
1✔
600

601
varIncrementReasoned :: Solver -> Var -> IO ()
602
varIncrementReasoned solver v = Vec.unsafeModify (svVarReasoned solver) (v - 1) (+1)
1✔
603

604
varEMADecay :: Solver -> IO ()
605
varEMADecay solver = do
1✔
606
  config <- getConfig solver
1✔
607

608
  alpha <- readIOURef (svERWAStepSize solver)
1✔
609
  let alphaMin = configERWAStepSizeMin config
1✔
610
  when (alpha > alphaMin) $ do
1✔
611
    writeIOURef (svERWAStepSize solver) (max alphaMin (alpha - configERWAStepSizeDec config))
1✔
612

613
  case configBranchingStrategy config of
1✔
614
    BranchingLRB -> do
1✔
615
      modifyIOURef (svEMAScale solver) (configEMADecay config *)
1✔
616
      scale <- readIOURef (svEMAScale solver)
1✔
617
      when (scale > 1e20) $ do
×
618
        n <- getNVars solver
×
619
        let a = svVarEMAScaled solver
×
620
        forLoop 0 (<n) (+1) $ \i -> Vec.unsafeModify a i (/ scale)
×
621
        writeIOURef (svEMAScale solver) 1.0
×
622
    _ -> return ()
×
623

624
variables :: Solver -> IO [Var]
625
variables solver = do
×
626
  n <- getNVars solver
×
627
  return [1 .. n]
×
628

629
-- | number of variables of the problem.
630
getNVars :: Solver -> IO Int
631
getNVars solver = Vec.getSize (svVarValue solver)
1✔
632

633
-- | number of assigned
634
getNAssigned :: Solver -> IO Int
635
getNAssigned solver = Vec.getSize (svTrail solver)
1✔
636

637
-- | number of constraints.
638
getNConstraints :: Solver -> IO Int
639
getNConstraints solver = do
1✔
640
  xs <- readIORef (svConstrDB solver)
1✔
641
  return $ length xs
1✔
642

643
-- | number of learnt constrints.
644
getNLearntConstraints :: Solver -> IO Int
645
getNLearntConstraints solver = do
1✔
646
  (n,_) <- readIORef (svLearntDB solver)
1✔
647
  return n
1✔
648

649
learntConstraints :: Solver -> IO [SomeConstraintHandler]
650
learntConstraints solver = do
×
651
  (_,cs) <- readIORef (svLearntDB solver)
×
652
  return cs
×
653

654
{--------------------------------------------------------------------
655
  Solver
656
--------------------------------------------------------------------}
657

658
-- | Create a new 'Solver' instance.
659
newSolver :: IO Solver
660
newSolver = newSolverWithConfig def
1✔
661

662
-- | Create a new 'Solver' instance with a given configulation.
663
newSolverWithConfig :: Config -> IO Solver
664
newSolverWithConfig config = do
1✔
665
 rec
666
  ok   <- newIORef True
1✔
667
  trail <- Vec.new
1✔
668
  trail_lim <- Vec.new
1✔
669
  trail_nprop <- newIOURef 0
1✔
670

671
  varValue <- Vec.new
1✔
672
  varPolarity <- Vec.new
1✔
673
  varActivity <- Vec.new
1✔
674
  varTrailIndex <- Vec.new
1✔
675
  varLevel <- Vec.new
1✔
676
  varWatches <- Vec.new
1✔
677
  varOnUnassigned <- Vec.new
1✔
678
  varReason <- Vec.new
1✔
679
  varEMAScaled <- Vec.new
1✔
680
  varWhenAssigned <- Vec.new
1✔
681
  varParticipated <- Vec.new
1✔
682
  varReasoned <- Vec.new
1✔
683
  litWatches <- Vec.new
1✔
684
  litOccurList <- Vec.new
1✔
685

686
  vqueue <- PQ.newPriorityQueueBy (ltVar solver)
1✔
687
  db  <- newIORef []
1✔
688
  db2 <- newIORef (0,[])
1✔
689
  as  <- Vec.new
1✔
690
  m   <- newIORef Nothing
×
691
  canceled <- newIORef False
×
692
  ndecision <- newIOURef 0
1✔
693
  nranddec  <- newIOURef 0
1✔
694
  nconflict <- newIOURef 0
1✔
695
  nrestart  <- newIOURef 0
1✔
696
  nlearntgc <- newIOURef 0
1✔
697
  nremoved  <- newIOURef 0
1✔
698

699
  constrInc   <- newIOURef 1
1✔
700
  varInc   <- newIOURef 1
1✔
701

702
  configRef <- newIORef config
1✔
703

704
  learntLim       <- newIORef undefined
×
705
  learntLimAdjCnt <- newIORef (-1)
1✔
706
  learntLimSeq    <- newIORef undefined
×
707

708
  logger <- newIORef Nothing
1✔
709
  startWC    <- newIORef undefined
×
710
  lastStatWC <- newIORef undefined
×
711

712
  randgen  <- newIORef =<< Rand.create
1✔
713

714
  failed <- newIORef IS.empty
×
715
  implied <- newIORef IS.empty
×
716

717
  confBudget <- newIOURef (-1)
1✔
718
  terminateCallback <- newIORef Nothing
1✔
719
  learntCallback <- newIORef Nothing
1✔
720

721
  tsolver <- newIORef Nothing
1✔
722
  tchecked <- newIOURef 0
1✔
723

724
  seen <- Vec.new
1✔
725
  pbLearnt <- newIORef Nothing
×
726

727
  alpha <- newIOURef 0.4
1✔
728
  emaScale <- newIOURef 1.0
1✔
729
  learntCounter <- newIOURef 0
1✔
730

731
  let solver =
1✔
732
        Solver
1✔
733
        { svOk = ok
1✔
734
        , svVarQueue   = vqueue
1✔
735
        , svTrail      = trail
1✔
736
        , svTrailLimit = trail_lim
1✔
737
        , svTrailNPropagated = trail_nprop
1✔
738

739
        , svVarValue        = varValue
1✔
740
        , svVarPolarity     = varPolarity
1✔
741
        , svVarActivity     = varActivity
1✔
742
        , svVarTrailIndex   = varTrailIndex
1✔
743
        , svVarLevel        = varLevel
1✔
744
        , svVarWatches      = varWatches
1✔
745
        , svVarOnUnassigned = varOnUnassigned
1✔
746
        , svVarReason       = varReason
1✔
747
        , svVarEMAScaled    = varEMAScaled
1✔
748
        , svVarWhenAssigned = varWhenAssigned
1✔
749
        , svVarParticipated = varParticipated
1✔
750
        , svVarReasoned     = varReasoned
1✔
751
        , svLitWatches      = litWatches
1✔
752
        , svLitOccurList    = litOccurList
1✔
753

754
        , svConstrDB   = db
1✔
755
        , svLearntDB   = db2
1✔
756

757
        -- Theory
758
        , svTheorySolver  = tsolver
1✔
759
        , svTheoryChecked = tchecked
1✔
760

761
        -- Result
762
        , svModel      = m
1✔
763
        , svFailedAssumptions = failed
1✔
764
        , svAssumptionsImplications = implied
1✔
765

766
        -- Statistics
767
        , svNDecision  = ndecision
1✔
768
        , svNRandomDecision = nranddec
1✔
769
        , svNConflict  = nconflict
1✔
770
        , svNRestart   = nrestart
1✔
771
        , svNLearntGC  = nlearntgc
1✔
772
        , svNRemovedConstr = nremoved
1✔
773

774
        -- Configulation
775
        , svConfig     = configRef
1✔
776
        , svRandomGen  = randgen
1✔
777
        , svConfBudget = confBudget
1✔
778
        , svTerminateCallback = terminateCallback
1✔
779
        , svLearnCallback = learntCallback
1✔
780

781
        -- Logging
782
        , svLogger = logger
1✔
783
        , svStartWC    = startWC
1✔
784
        , svLastStatWC = lastStatWC
1✔
785

786
        -- Working space
787
        , svCanceled        = canceled
1✔
788
        , svAssumptions     = as
1✔
789
        , svLearntLim       = learntLim
1✔
790
        , svLearntLimAdjCnt = learntLimAdjCnt
1✔
791
        , svLearntLimSeq    = learntLimSeq
1✔
792
        , svVarInc      = varInc
1✔
793
        , svConstrInc   = constrInc
1✔
794
        , svSeen = seen
1✔
795
        , svPBLearnt = pbLearnt
1✔
796

797
        , svERWAStepSize = alpha
1✔
798
        , svEMAScale = emaScale
1✔
799
        , svLearntCounter = learntCounter
1✔
800
        }
801
 return solver
1✔
802

803
ltVar :: Solver -> Var -> Var -> IO Bool
804
ltVar solver !v1 !v2 = do
1✔
805
  conf <- getConfig solver
1✔
806
  case configBranchingStrategy conf of
1✔
807
    BranchingVSIDS -> do
1✔
808
      a1 <- varActivity solver v1
1✔
809
      a2 <- varActivity solver v2
1✔
810
      return $! a1 > a2
1✔
811
    _ -> do -- BranchingERWA and BranchingLRB
1✔
812
      a1 <- varEMAScaled solver v1
1✔
813
      a2 <- varEMAScaled solver v1
1✔
814
      return $! a1 > a2
1✔
815

816
{--------------------------------------------------------------------
817
  Problem specification
818
--------------------------------------------------------------------}
819

820
instance NewVar IO Solver where
821
  newVar :: Solver -> IO Var
822
  newVar solver = do
1✔
823
    n <- Vec.getSize (svVarValue solver)
1✔
824
#if SIZEOF_HSINT > 4
825
    when (n == fromIntegral (maxBound :: PackedLit)) $ do
×
826
      error "cannot allocate more variables"
×
827
#endif
828
    let v = n + 1
1✔
829

830
    Vec.push (svVarValue solver) (coerce lUndef)
1✔
831
    Vec.push (svVarPolarity solver) True
1✔
832
    Vec.push (svVarActivity solver) 0
1✔
833
    Vec.push (svVarTrailIndex solver) maxBound
1✔
834
    Vec.push (svVarLevel solver) maxBound
1✔
835
    Vec.push (svVarWatches solver) []
1✔
836
    Vec.push (svVarOnUnassigned solver) []
1✔
837
    Vec.push (svVarReason solver) Nothing
×
838
    Vec.push (svVarEMAScaled solver) 0
1✔
839
    Vec.push (svVarWhenAssigned solver) (-1)
1✔
840
    Vec.push (svVarParticipated solver) 0
1✔
841
    Vec.push (svVarReasoned solver) 0
1✔
842

843
    Vec.push (svLitWatches solver) []
1✔
844
    Vec.push (svLitWatches solver) []
1✔
845
    Vec.push (svLitOccurList solver) HashSet.empty
1✔
846
    Vec.push (svLitOccurList solver) HashSet.empty
1✔
847

848
    PQ.enqueue (svVarQueue solver) v
1✔
849
    Vec.push (svSeen solver) False
1✔
850
    return v
1✔
851

852
  newVars :: Solver -> Int -> IO [Var]
853
  newVars solver n = do
1✔
854
    nv <- getNVars solver
1✔
855
#if SIZEOF_HSINT > 4
856
    when (nv + n > fromIntegral (maxBound :: PackedLit)) $ do
×
857
      error "cannot allocate more variables"
×
858
#endif
859
    resizeVarCapacity solver (nv+n)
1✔
860
    replicateM n (newVar solver)
1✔
861

862
  newVars_ :: Solver -> Int -> IO ()
863
  newVars_ solver n = do
1✔
864
    nv <- getNVars solver
1✔
865
#if SIZEOF_HSINT > 4
866
    when (nv + n > fromIntegral (maxBound :: PackedLit)) $ do
×
867
      error "cannot allocate more variables"
×
868
#endif
869
    resizeVarCapacity solver (nv+n)
1✔
870
    replicateM_ n (newVar solver)
1✔
871

872
-- |Pre-allocate internal buffer for @n@ variables.
873
resizeVarCapacity :: Solver -> Int -> IO ()
874
resizeVarCapacity solver n = do
1✔
875
  Vec.resizeCapacity (svVarValue solver) n
1✔
876
  Vec.resizeCapacity (svVarPolarity solver) n
1✔
877
  Vec.resizeCapacity (svVarActivity solver) n
1✔
878
  Vec.resizeCapacity (svVarTrailIndex solver) n
1✔
879
  Vec.resizeCapacity (svVarLevel solver) n
1✔
880
  Vec.resizeCapacity (svVarWatches solver) n
1✔
881
  Vec.resizeCapacity (svVarOnUnassigned solver) n
1✔
882
  Vec.resizeCapacity (svVarReason solver) n
1✔
883
  Vec.resizeCapacity (svVarEMAScaled solver) n
1✔
884
  Vec.resizeCapacity (svVarWhenAssigned solver) n
1✔
885
  Vec.resizeCapacity (svVarParticipated solver) n
1✔
886
  Vec.resizeCapacity (svVarReasoned solver) n
1✔
887
  Vec.resizeCapacity (svLitWatches solver) (n*2)
1✔
888
  Vec.resizeCapacity (svLitOccurList solver) (n*2)
1✔
889
  Vec.resizeCapacity (svSeen solver) n
1✔
890
  PQ.resizeHeapCapacity (svVarQueue solver) n
1✔
891
  PQ.resizeTableCapacity (svVarQueue solver) (n+1)
1✔
892

893
instance AddClause IO Solver where
894
  addClause :: Solver -> Clause -> IO ()
895
  addClause solver lits = do
1✔
896
    d <- getDecisionLevel solver
1✔
897
    assert (d == levelRoot) $ return ()
×
898

899
    ok <- readIORef (svOk solver)
1✔
900
    when ok $ do
1✔
901
      m <- instantiateClause (getLitFixed solver) lits
1✔
902
      case normalizeClause =<< m of
1✔
903
        Nothing -> return ()
×
904
        Just [] -> markBad solver
1✔
905
        Just [lit] -> do
1✔
906
          {- We do not call 'removeBackwardSubsumedBy' here,
907
             because subsumed constraints will be removed by 'simplify'. -}
908
          ret <- assign solver lit
1✔
909
          assert ret $ return ()
×
910
          ret2 <- deduce solver
1✔
911
          case ret2 of
1✔
912
            Nothing -> return ()
×
913
            Just _ -> markBad solver
1✔
914
        Just lits2 -> do
1✔
915
          subsumed <- checkForwardSubsumption solver lits
1✔
916
          unless subsumed $ do
1✔
917
            removeBackwardSubsumedBy solver ([(1,lit) | lit <- lits2], 1)
1✔
918
            clause <- newClauseHandler lits2 False
1✔
919
            addToDB solver clause
1✔
920
            _ <- basicAttachClauseHandler solver clause
1✔
921
            return ()
×
922

923
instance AddCardinality IO Solver where
924
  addAtLeast :: Solver -> [Lit] -> Int -> IO ()
925
  addAtLeast solver lits n = do
1✔
926
    d <- getDecisionLevel solver
1✔
927
    assert (d == levelRoot) $ return ()
×
928

929
    ok <- readIORef (svOk solver)
1✔
930
    when ok $ do
1✔
931
      (lits',n') <- liftM normalizeAtLeast $ instantiateAtLeast (getLitFixed solver) (lits,n)
1✔
932
      let len = length lits'
1✔
933

934
      if n' <= 0 then return ()
×
935
      else if n' > len then markBad solver
1✔
936
      else if n' == 1 then addClause solver lits'
1✔
937
      else if n' == len then do
1✔
938
        {- We do not call 'removeBackwardSubsumedBy' here,
939
           because subsumed constraints will be removed by 'simplify'. -}
940
        forM_ lits' $ \l -> do
1✔
941
          ret <- assign solver l
1✔
942
          assert ret $ return ()
×
943
        ret2 <- deduce solver
1✔
944
        case ret2 of
1✔
945
          Nothing -> return ()
×
946
          Just _ -> markBad solver
1✔
947
      else do -- n' < len
1✔
948
        removeBackwardSubsumedBy solver ([(1,lit) | lit <- lits'], fromIntegral n')
×
949
        c <- newAtLeastHandler lits' n' False
1✔
950
        addToDB solver c
1✔
951
        _ <- basicAttachAtLeastHandler solver c
1✔
952
        return ()
×
953

954
instance AddPBLin IO Solver where
955
  addPBAtLeast :: Solver -> PBLinSum -> Integer -> IO ()
956
  addPBAtLeast solver ts n = do
1✔
957
    d <- getDecisionLevel solver
1✔
958
    assert (d == levelRoot) $ return ()
×
959

960
    ok <- readIORef (svOk solver)
1✔
961
    when ok $ do
1✔
962
      (ts',n') <- liftM normalizePBLinAtLeast $ instantiatePBLinAtLeast (getLitFixed solver) (ts,n)
1✔
963

964
      case pbToAtLeast (ts',n') of
1✔
965
        Just (lhs',rhs') -> addAtLeast solver lhs' rhs'
1✔
966
        Nothing -> do
1✔
967
          let cs = map fst ts'
1✔
968
              slack = sum cs - n'
1✔
969
          if n' <= 0 then return ()
×
970
          else if slack < 0 then markBad solver
1✔
971
          else do
1✔
972
            removeBackwardSubsumedBy solver (ts', n')
1✔
973
            (ts'',n'') <- do
1✔
974
              b <- configEnablePBSplitClausePart <$> getConfig solver
1✔
975
              if b
1✔
976
              then pbSplitClausePart solver (ts',n')
1✔
977
              else return (ts',n')
1✔
978

979
            c <- newPBHandler solver ts'' n'' False
1✔
980
            let constr = toConstraintHandler c
1✔
981
            addToDB solver constr
1✔
982
            ret <- attach solver constr
1✔
983
            if not ret then do
×
984
              markBad solver
×
985
            else do
1✔
986
              ret2 <- deduce solver
1✔
987
              case ret2 of
1✔
988
                Nothing -> return ()
×
989
                Just _ -> markBad solver
1✔
990

991
  addPBExactly :: Solver -> PBLinSum -> Integer -> IO ()
992
  addPBExactly solver ts n = do
1✔
993
    (ts2,n2) <- liftM normalizePBLinExactly $ instantiatePBLinExactly (getLitFixed solver) (ts,n)
1✔
994
    addPBAtLeast solver ts2 n2
1✔
995
    addPBAtMost solver ts2 n2
1✔
996

997
  addPBAtLeastSoft :: Solver -> Lit -> PBLinSum -> Integer -> IO ()
998
  addPBAtLeastSoft solver sel lhs rhs = do
1✔
999
    (lhs', rhs') <- liftM normalizePBLinAtLeast $ instantiatePBLinAtLeast (getLitFixed solver) (lhs,rhs)
1✔
1000
    addPBAtLeast solver ((rhs', litNot sel) : lhs') rhs'
1✔
1001

1002
  addPBExactlySoft :: Solver -> Lit -> PBLinSum -> Integer -> IO ()
1003
  addPBExactlySoft solver sel lhs rhs = do
1✔
1004
    (lhs2, rhs2) <- liftM normalizePBLinExactly $ instantiatePBLinExactly (getLitFixed solver) (lhs,rhs)
1✔
1005
    addPBAtLeastSoft solver sel lhs2 rhs2
1✔
1006
    addPBAtMostSoft solver sel lhs2 rhs2
1✔
1007

1008
-- | See documentation of 'setPBSplitClausePart'.
1009
pbSplitClausePart :: Solver -> PBLinAtLeast -> IO PBLinAtLeast
1010
pbSplitClausePart solver (lhs,rhs) = do
1✔
1011
  let (ts1,ts2) = partition (\(c,_) -> c >= rhs) lhs
1✔
1012
  if length ts1 < 2 then
1✔
1013
    return (lhs,rhs)
1✔
1014
  else do
1✔
1015
    sel <- newVar solver
1✔
1016
    addClause solver $ -sel : [l | (_,l) <- ts1]
1✔
1017
    return ((rhs,sel) : ts2, rhs)
1✔
1018

1019
instance AddXORClause IO Solver where
1020
  addXORClause :: Solver -> [Lit] -> Bool -> IO ()
1021
  addXORClause solver lits rhs = do
1✔
1022
    d <- getDecisionLevel solver
1✔
1023
    assert (d == levelRoot) $ return ()
×
1024

1025
    ok <- readIORef (svOk solver)
1✔
1026
    when ok $ do
1✔
1027
      xcl <- instantiateXORClause (getLitFixed solver) (lits,rhs)
1✔
1028
      case normalizeXORClause xcl of
1✔
1029
        ([], True) -> markBad solver
1✔
1030
        ([], False) -> return ()
×
1031
        ([l], b) -> addClause solver [if b then l else litNot l]
1✔
1032
        (l:ls, b) -> do
1✔
1033
          c <- newXORClauseHandler ((if b then l else litNot l) : ls) False
1✔
1034
          addToDB solver c
1✔
1035
          _ <- basicAttachXORClauseHandler solver c
1✔
1036
          return ()
×
1037

1038
{--------------------------------------------------------------------
1039
  Problem solving
1040
--------------------------------------------------------------------}
1041

1042
-- | Solve constraints.
1043
-- Returns 'True' if the problem is SATISFIABLE.
1044
-- Returns 'False' if the problem is UNSATISFIABLE.
1045
solve :: Solver -> IO Bool
1046
solve solver = do
1✔
1047
  Vec.clear (svAssumptions solver)
1✔
1048
  solve_ solver
1✔
1049

1050
-- | Solve constraints under assuptions.
1051
-- Returns 'True' if the problem is SATISFIABLE.
1052
-- Returns 'False' if the problem is UNSATISFIABLE.
1053
solveWith :: Solver
1054
          -> [Lit]    -- ^ Assumptions
1055
          -> IO Bool
1056
solveWith solver ls = do
1✔
1057
  Vec.clear (svAssumptions solver)
1✔
1058
  mapM_ (Vec.push (svAssumptions solver)) ls
1✔
1059
  solve_ solver
1✔
1060

1061
solve_ :: Solver -> IO Bool
1062
solve_ solver = do
1✔
1063
  config <- getConfig solver
1✔
1064
  writeIORef (svAssumptionsImplications solver) IS.empty
1✔
1065

1066
  log solver "Solving starts ..."
×
1067
  resetStat solver
1✔
1068
  writeIORef (svCanceled solver) False
1✔
1069
  writeIORef (svModel solver) Nothing
×
1070
  writeIORef (svFailedAssumptions solver) IS.empty
1✔
1071

1072
  ok <- readIORef (svOk solver)
1✔
1073
  if not ok then
1✔
1074
    return False
1✔
1075
  else do
1✔
1076
    when debugMode $ dumpVarActivity solver
×
1077
    d <- getDecisionLevel solver
1✔
1078
    assert (d == levelRoot) $ return ()
×
1079

1080
    nv <- getNVars solver
1✔
1081
    Vec.resizeCapacity (svTrail solver) nv
1✔
1082

1083
    unless (configRestartInc config > 1) $ error "RestartInc must be >1"
×
1084
    let restartSeq =
1✔
1085
          if configRestartFirst config  > 0
1✔
1086
          then mkRestartSeq (configRestartStrategy config) (configRestartFirst config) (configRestartInc config)
1✔
1087
          else repeat 0
1✔
1088

1089
    let learntSizeAdj = do
1✔
1090
          (size,adj) <- shift (svLearntLimSeq solver)
1✔
1091
          writeIORef (svLearntLim solver) size
1✔
1092
          writeIORef (svLearntLimAdjCnt solver) adj
1✔
1093
        onConflict = do
1✔
1094
          cnt <- readIORef (svLearntLimAdjCnt solver)
1✔
1095
          if (cnt==0)
1✔
1096
          then learntSizeAdj
1✔
1097
          else writeIORef (svLearntLimAdjCnt solver) $! cnt-1
1✔
1098

1099
    cnt <- readIORef (svLearntLimAdjCnt solver)
1✔
1100
    when (cnt == -1) $ do
1✔
1101
      unless (configLearntSizeInc config > 1) $ error "LearntSizeInc must be >1"
×
1102
      nc <- getNConstraints solver
1✔
1103
      let initialLearntLim = if configLearntSizeFirst config > 0 then configLearntSizeFirst config else max ((nc + nv) `div` 3) 16
1✔
1104
          learntSizeSeq    = iterate (ceiling . (configLearntSizeInc config *) . fromIntegral) initialLearntLim
1✔
1105
          learntSizeAdjSeq = iterate (\x -> (x * 3) `div` 2) (100::Int)
1✔
1106
      writeIORef (svLearntLimSeq solver) (zip learntSizeSeq learntSizeAdjSeq)
1✔
1107
      learntSizeAdj
1✔
1108

1109
    unless (0 <= configERWAStepSizeFirst config && configERWAStepSizeFirst config <= 1) $
1✔
1110
      error "ERWAStepSizeFirst must be in [0..1]"
×
1111
    unless (0 <= configERWAStepSizeMin config && configERWAStepSizeFirst config <= 1) $
1✔
1112
      error "ERWAStepSizeMin must be in [0..1]"
×
1113
    unless (0 <= configERWAStepSizeDec config) $
1✔
1114
      error "ERWAStepSizeDec must be >=0"
×
1115
    writeIOURef (svERWAStepSize solver) (configERWAStepSizeFirst config)
1✔
1116

1117
    let loop [] = error "solve_: should not happen"
×
1118
        loop (conflict_lim:rs) = do
1✔
1119
          printStat solver True
1✔
1120
          ret <- search solver conflict_lim onConflict
1✔
1121
          case ret of
1✔
1122
            SRFinished x -> return $ Right x
1✔
1123
            SRBudgetExceeded -> return $ Left (throw BudgetExceeded)
×
1124
            SRCanceled -> return $ Left (throw Canceled)
×
1125
            SRRestart -> do
1✔
1126
              modifyIOURef (svNRestart solver) (+1)
1✔
1127
              backtrackTo solver levelRoot
1✔
1128
              loop rs
1✔
1129

1130
    printStatHeader solver
1✔
1131

1132
    startCPU <- getTime ProcessCPUTime
1✔
1133
    startWC  <- getTime Monotonic
1✔
1134
    writeIORef (svStartWC solver) startWC
×
1135
    result <- loop restartSeq
1✔
1136
    endCPU <- getTime ProcessCPUTime
1✔
1137
    endWC  <- getTime Monotonic
1✔
1138

1139
    case result of
1✔
1140
      Right True -> do
1✔
1141
        when (configCheckModel config) $ checkSatisfied solver
1✔
1142
        constructModel solver
1✔
1143
        mt <- getTheory solver
1✔
1144
        case mt of
1✔
1145
          Nothing -> return ()
×
1146
          Just t -> thConstructModel t
1✔
1147
      _ -> return ()
×
1148
    case result of
1✔
1149
      Right False -> return ()
×
1150
      _ -> saveAssumptionsImplications solver
1✔
1151

1152
    backtrackTo solver levelRoot
1✔
1153

1154
    when debugMode $ dumpVarActivity solver
×
1155
    when debugMode $ dumpConstrActivity solver
×
1156
    printStat solver True
1✔
1157
    let durationSecs :: TimeSpec -> TimeSpec -> Double
1158
        durationSecs start end = fromIntegral (toNanoSecs (end `diffTimeSpec` start)) / 10^(9::Int)
×
1159
    (log solver . printf "#cpu_time = %.3fs") (durationSecs startCPU endCPU)
×
1160
    (log solver . printf "#wall_clock_time = %.3fs") (durationSecs startWC endWC)
×
1161
    (log solver . printf "#decision = %d") =<< readIOURef (svNDecision solver)
×
1162
    (log solver . printf "#random_decision = %d") =<< readIOURef (svNRandomDecision solver)
×
1163
    (log solver . printf "#conflict = %d") =<< readIOURef (svNConflict solver)
×
1164
    (log solver . printf "#restart = %d")  =<< readIOURef (svNRestart solver)
×
1165

1166
    case result of
1✔
1167
      Right x  -> return x
1✔
1168
      Left m -> m
1✔
1169

1170
data BudgetExceeded = BudgetExceeded
1171
  deriving (Show, Typeable)
×
1172

1173
instance Exception BudgetExceeded
1174

1175
data Canceled = Canceled
1176
  deriving (Show, Typeable)
×
1177

1178
instance Exception Canceled
1179

1180
data SearchResult
1181
  = SRFinished Bool
1182
  | SRRestart
1183
  | SRBudgetExceeded
1184
  | SRCanceled
1185

1186
search :: Solver -> Int -> IO () -> IO SearchResult
1187
search solver !conflict_lim onConflict = do
1✔
1188
  conflictCounter <- newIORef 0
1✔
1189
  let
1190
    loop :: IO SearchResult
1191
    loop = do
1✔
1192
      conflict <- deduce solver
1✔
1193
      case conflict of
1✔
1194
        Just constr -> do
1✔
1195
          ret <- handleConflict conflictCounter constr
1✔
1196
          case ret of
1✔
1197
            Just sr -> return sr
1✔
1198
            Nothing -> loop
1✔
1199
        Nothing -> do
1✔
1200
          lv <- getDecisionLevel solver
1✔
1201
          when (lv == levelRoot) $ simplify solver
1✔
1202
          checkGC
1✔
1203
          r <- pickAssumption
1✔
1204
          case r of
1✔
1205
            Nothing -> return (SRFinished False)
1✔
1206
            Just lit
1207
              | lit /= litUndef -> decide solver lit >> loop
1✔
1208
              | otherwise -> do
1✔
1209
                  lit2 <- pickBranchLit solver
1✔
1210
                  if lit2 == litUndef
1✔
1211
                    then return (SRFinished True)
1✔
1212
                    else decide solver lit2 >> loop
1✔
1213
  loop
1✔
1214

1215
  where
1216
    checkGC :: IO ()
1217
    checkGC = do
1✔
1218
      n <- getNLearntConstraints solver
1✔
1219
      m <- getNAssigned solver
1✔
1220
      learnt_lim <- readIORef (svLearntLim solver)
1✔
1221
      when (learnt_lim >= 0 && n - m > learnt_lim) $ do
1✔
1222
        modifyIOURef (svNLearntGC solver) (+1)
1✔
1223
        reduceDB solver
1✔
1224

1225
    pickAssumption :: IO (Maybe Lit)
1226
    pickAssumption = do
1✔
1227
      s <- Vec.getSize (svAssumptions solver)
1✔
1228
      let go = do
1✔
1229
              d <- getDecisionLevel solver
1✔
1230
              if not (d < s) then
1✔
1231
                return (Just litUndef)
1✔
1232
              else do
1✔
1233
                l <- Vec.unsafeRead (svAssumptions solver) d
1✔
1234
                val <- litValue solver l
1✔
1235
                if val == lTrue then do
1✔
1236
                  -- dummy decision level
1237
                  pushDecisionLevel solver
1✔
1238
                  go
1✔
1239
                else if val == lFalse then do
1✔
1240
                  -- conflict with assumption
1241
                  core <- analyzeFinal solver l
1✔
1242
                  writeIORef (svFailedAssumptions solver) (IS.fromList core)
1✔
1243
                  return Nothing
1✔
1244
                else
1245
                  return (Just l)
1✔
1246
      go
1✔
1247

1248
    handleConflict :: IORef Int -> SomeConstraintHandler -> IO (Maybe SearchResult)
1249
    handleConflict conflictCounter constr = do
1✔
1250
      varEMADecay solver
1✔
1251
      varDecayActivity solver
1✔
1252
      constrDecayActivity solver
1✔
1253
      onConflict
1✔
1254

1255
      modifyIOURef (svNConflict solver) (+1)
1✔
1256
      d <- getDecisionLevel solver
1✔
1257

1258
      when debugMode $ logIO solver $ do
×
1259
        str <- showConstraintHandler constr
×
1260
        return $ printf "conflict(level=%d): %s" d str
×
1261

1262
      modifyIORef' conflictCounter (+1)
1✔
1263
      c <- readIORef conflictCounter
1✔
1264

1265
      modifyIOURef (svConfBudget solver) $ \confBudget ->
1✔
1266
        if confBudget > 0 then confBudget - 1 else confBudget
×
1267
      confBudget <- readIOURef (svConfBudget solver)
1✔
1268

1269
      terminateCallback' <- readIORef (svTerminateCallback solver)
1✔
1270
      case terminateCallback' of
1✔
1271
        Nothing -> return ()
×
1272
        Just terminateCallback -> do
1✔
1273
          ret <- terminateCallback
1✔
1274
          when ret $ writeIORef (svCanceled solver) True
1✔
1275
      canceled <- readIORef (svCanceled solver)
1✔
1276

1277
      when (c `mod` 100 == 0) $ do
1✔
1278
        printStat solver False
1✔
1279

1280
      if d == levelRoot then do
1✔
1281
        callLearnCallback solver []
×
1282
        markBad solver
1✔
1283
        return $ Just (SRFinished False)
1✔
1284
      else if confBudget==0 then
×
1285
        return $ Just SRBudgetExceeded
×
1286
      else if canceled then
1✔
1287
        return $ Just SRCanceled
1✔
1288
      else if conflict_lim > 0 && c >= conflict_lim then
1✔
1289
        return $ Just SRRestart
1✔
1290
      else do
1✔
1291
        modifyIOURef (svLearntCounter solver) (+1)
1✔
1292
        config <- getConfig solver
1✔
1293
        case configLearningStrategy config of
1✔
1294
          LearningClause -> learnClause constr >> return Nothing
1✔
1295
          LearningHybrid -> learnHybrid conflictCounter constr
1✔
1296

1297
    learnClause :: SomeConstraintHandler -> IO ()
1298
    learnClause constr = do
1✔
1299
      (learntClause, level) <- analyzeConflict solver constr
1✔
1300
      backtrackTo solver level
1✔
1301
      case learntClause of
1✔
1302
        [] -> error "search(LearningClause): should not happen"
×
1303
        [lit] -> do
1✔
1304
          ret <- assign solver lit
1✔
1305
          assert ret $ return ()
×
1306
          return ()
×
1307
        lit:_ -> do
1✔
1308
          cl <- newClauseHandler learntClause True
1✔
1309
          let constr2 = toConstraintHandler cl
1✔
1310
          addToLearntDB solver constr2
1✔
1311
          basicAttachClauseHandler solver cl
1✔
1312
          assignBy solver lit constr2
1✔
1313
          constrBumpActivity solver constr2
1✔
1314

1315
    learnHybrid :: IORef Int -> SomeConstraintHandler -> IO (Maybe SearchResult)
1316
    learnHybrid conflictCounter constr = do
1✔
1317
      (learntClause, clauseLevel) <- analyzeConflict solver constr
1✔
1318
      (pb, minLevel) <- do
1✔
1319
        z <- readIORef (svPBLearnt solver)
1✔
1320
        case z of
1✔
1321
          Nothing -> return (z, clauseLevel)
1✔
1322
          Just pb -> do
1✔
1323
            pbLevel <- pbBacktrackLevel solver pb
1✔
1324
            return (z, min clauseLevel pbLevel)
1✔
1325
      backtrackTo solver minLevel
1✔
1326

1327
      case learntClause of
1✔
1328
        [] -> error "search(LearningHybrid): should not happen"
×
1329
        [lit] -> do
1✔
1330
          _ <- assign solver lit -- This should always succeed.
1✔
1331
          return ()
×
1332
        lit:_ -> do
1✔
1333
          cl <- newClauseHandler learntClause True
1✔
1334
          let constr2 = toConstraintHandler cl
1✔
1335
          addToLearntDB solver constr2
1✔
1336
          basicAttachClauseHandler solver cl
1✔
1337
          constrBumpActivity solver constr2
1✔
1338
          when (minLevel == clauseLevel) $ do
1✔
1339
            _ <- assignBy solver lit constr2 -- This should always succeed.
1✔
1340
            return ()
×
1341

1342
      ret <- deduce solver
1✔
1343
      case ret of
1✔
1344
        Just conflicted -> do
1✔
1345
          handleConflict conflictCounter conflicted
1✔
1346
          -- TODO: should also learn the PB constraint?
1347
        Nothing -> do
1✔
1348
          case pb of
1✔
1349
            Nothing -> return Nothing
1✔
1350
            Just (lhs,rhs) -> do
1✔
1351
              h <- newPBHandlerPromoted solver lhs rhs True
1✔
1352
              case h of
1✔
1353
                CHClause _ -> do
×
1354
                  {- We don't want to add additional clause,
1355
                     since it would be subsumed by already added one. -}
1356
                  return Nothing
×
1357
                _ -> do
1✔
1358
                  addToLearntDB solver h
1✔
1359
                  ret2 <- attach solver h
1✔
1360
                  constrBumpActivity solver h
1✔
1361
                  if ret2 then
×
1362
                    return Nothing
1✔
1363
                  else
1364
                    handleConflict conflictCounter h
×
1365

1366
-- | Cancel exectution of 'solve' or 'solveWith'.
1367
--
1368
-- This can be called from other threads.
1369
cancel :: Solver -> IO ()
1370
cancel solver = writeIORef (svCanceled solver) True
×
1371

1372
-- | After 'solve' returns True, it returns an satisfying assignment.
1373
getModel :: Solver -> IO Model
1374
getModel solver = do
1✔
1375
  m <- readIORef (svModel solver)
1✔
1376
  return (fromJust m)
1✔
1377

1378
-- | After 'solveWith' returns False, it returns a set of assumptions
1379
-- that leads to contradiction. In particular, if it returns an empty
1380
-- set, the problem is unsatisiable without any assumptions.
1381
getFailedAssumptions :: Solver -> IO LitSet
1382
getFailedAssumptions solver = readIORef (svFailedAssumptions solver)
1✔
1383

1384
-- | __EXPERIMENTAL API__: After 'solveWith' returns True or failed with 'BudgetExceeded' exception,
1385
-- it returns a set of literals that are implied by assumptions.
1386
getAssumptionsImplications :: Solver -> IO LitSet
1387
getAssumptionsImplications solver = readIORef (svAssumptionsImplications solver)
1✔
1388

1389
{--------------------------------------------------------------------
1390
  Simplification
1391
--------------------------------------------------------------------}
1392

1393
-- | Simplify the constraint database according to the current top-level assigment.
1394
simplify :: Solver -> IO ()
1395
simplify solver = do
1✔
1396
  let loop [] rs !n     = return (rs,n)
1✔
1397
      loop (y:ys) rs !n = do
1✔
1398
        b1 <- isSatisfied solver y
1✔
1399
        b2 <- isLocked solver y
1✔
1400
        if b1 && not b2 then do
1✔
1401
          detach solver y
1✔
1402
          loop ys rs (n+1)
1✔
1403
        else loop ys (y:rs) n
1✔
1404

1405
  -- simplify original constraint DB
1406
  do
1✔
1407
    xs <- readIORef (svConstrDB solver)
1✔
1408
    (ys,n) <- loop xs [] (0::Int)
1✔
1409
    modifyIOURef (svNRemovedConstr solver) (+n)
1✔
1410
    writeIORef (svConstrDB solver) ys
1✔
1411

1412
  -- simplify learnt constraint DB
1413
  do
1✔
1414
    (m,xs) <- readIORef (svLearntDB solver)
1✔
1415
    (ys,n) <- loop xs [] (0::Int)
1✔
1416
    writeIORef (svLearntDB solver) (m-n, ys)
1✔
1417

1418
{-
1419
References:
1420
L. Zhang, "On subsumption removal and On-the-Fly CNF simplification,"
1421
Theory and Applications of Satisfiability Testing (2005), pp. 482-489.
1422
-}
1423

1424
checkForwardSubsumption :: Solver -> Clause -> IO Bool
1425
checkForwardSubsumption solver lits = do
1✔
1426
  flag <- configEnableForwardSubsumptionRemoval <$> getConfig solver
1✔
1427
  if not flag then
1✔
1428
    return False
1✔
1429
  else do
1✔
1430
    withEnablePhaseSaving False $ do
1✔
1431
      bracket_
1✔
1432
        (pushDecisionLevel solver)
1✔
1433
        (backtrackTo solver levelRoot) $ do
1✔
1434
          b <- allM (\lit -> assign solver (litNot lit)) lits
1✔
1435
          if b then
×
1436
            liftM isJust (deduce solver)
1✔
1437
          else do
×
1438
            when debugMode $ log solver ("forward subsumption: " ++ show lits)
×
1439
            return True
×
1440
  where
1441
    withEnablePhaseSaving flag m =
1✔
1442
      bracket
1✔
1443
        (getConfig solver)
1✔
1444
        (\saved -> modifyConfig solver (\config -> config{ configEnablePhaseSaving = configEnablePhaseSaving saved }))
1✔
1445
        (\saved -> setConfig solver saved{ configEnablePhaseSaving = flag } >> m)
1✔
1446

1447
removeBackwardSubsumedBy :: Solver -> PBLinAtLeast -> IO ()
1448
removeBackwardSubsumedBy solver pb = do
1✔
1449
  flag <- configEnableBackwardSubsumptionRemoval <$> getConfig solver
1✔
1450
  when flag $ do
1✔
1451
    xs <- backwardSubsumedBy solver pb
1✔
1452
    when debugMode $ do
×
1453
      forM_ (HashSet.toList xs) $ \c -> do
×
1454
        s <- showConstraintHandler c
×
1455
        log solver (printf "backward subsumption: %s is subsumed by %s\n" s (show pb))
×
1456
    removeConstraintHandlers solver xs
1✔
1457

1458
backwardSubsumedBy :: Solver -> PBLinAtLeast -> IO (HashSet SomeConstraintHandler)
1459
backwardSubsumedBy solver pb@(lhs,_) = do
1✔
1460
  xs <- forM lhs $ \(_,lit) -> do
1✔
1461
    Vec.unsafeRead (svLitOccurList solver) (litIndex lit)
1✔
1462
  case xs of
1✔
1463
    [] -> return HashSet.empty
×
1464
    s:ss -> do
1✔
1465
      let p c = do
1✔
1466
            -- Note that @isPBRepresentable c@ is always True here,
1467
            -- because only such constraints are added to occur list.
1468
            -- See 'addToDB'.
1469
            pb2 <- instantiatePBLinAtLeast (getLitFixed solver) =<< toPBLinAtLeast c
1✔
1470
            return $ pbLinSubsume pb pb2
1✔
1471
      liftM HashSet.fromList
1✔
1472
        $ filterM p
1✔
1473
        $ HashSet.toList
1✔
1474
        $ foldl' HashSet.intersection s ss
1✔
1475

1476
removeConstraintHandlers :: Solver -> HashSet SomeConstraintHandler -> IO ()
1477
removeConstraintHandlers _ zs | HashSet.null zs = return ()
×
1478
removeConstraintHandlers solver zs = do
1✔
1479
  let loop [] rs !n     = return (rs,n)
1✔
1480
      loop (c:cs) rs !n = do
1✔
1481
        if c `HashSet.member` zs then do
1✔
1482
          detach solver c
1✔
1483
          loop cs rs (n+1)
1✔
1484
        else loop cs (c:rs) n
1✔
1485
  xs <- readIORef (svConstrDB solver)
1✔
1486
  (ys,n) <- loop xs [] (0::Int)
1✔
1487
  modifyIOURef (svNRemovedConstr solver) (+n)
1✔
1488
  writeIORef (svConstrDB solver) ys
1✔
1489

1490
{--------------------------------------------------------------------
1491
  Parameter settings.
1492
--------------------------------------------------------------------}
1493

1494
{--------------------------------------------------------------------
1495
  Configulation
1496
--------------------------------------------------------------------}
1497

1498
getConfig :: Solver -> IO Config
1499
getConfig solver = readIORef $ svConfig solver
1✔
1500

1501
setConfig :: Solver -> Config -> IO ()
1502
setConfig solver conf = do
1✔
1503
  orig <- getConfig solver
1✔
1504
  writeIORef (svConfig solver) conf
1✔
1505
  when (configBranchingStrategy orig /= configBranchingStrategy conf) $ do
×
1506
    PQ.rebuild (svVarQueue solver)
×
1507

1508
modifyConfig :: Solver -> (Config -> Config) -> IO ()
1509
modifyConfig solver f = do
1✔
1510
  config <- getConfig solver
1✔
1511
  setConfig solver $ f config
1✔
1512

1513
-- | The default polarity of a variable.
1514
setVarPolarity :: Solver -> Var -> Bool -> IO ()
1515
setVarPolarity solver v val = Vec.unsafeWrite (svVarPolarity solver) (v - 1) val
1✔
1516

1517
-- | Set random generator used by the random variable selection
1518
setRandomGen :: Solver -> Rand.GenIO -> IO ()
1519
setRandomGen solver = writeIORef (svRandomGen solver)
1✔
1520

1521
-- | Get random generator used by the random variable selection
1522
getRandomGen :: Solver -> IO Rand.GenIO
1523
getRandomGen solver = readIORef (svRandomGen solver)
×
1524

1525
setConfBudget :: Solver -> Maybe Int -> IO ()
1526
setConfBudget solver (Just b) | b >= 0 = writeIOURef (svConfBudget solver) b
×
1527
setConfBudget solver _ = writeIOURef (svConfBudget solver) (-1)
×
1528

1529
-- | Set a callback function used to indicate a termination requirement to the solver.
1530
--
1531
-- The solver will periodically call this function and check its return value during
1532
-- the search. If the callback function returns `True` the solver terminates and throws
1533
-- 'Canceled' exception.
1534
--
1535
-- See also 'clearTerminateCallback' and
1536
-- [IPASIR](https://github.com/biotomas/ipasir)'s @ipasir_set_terminate()@ function.
1537
setTerminateCallback :: Solver -> IO Bool -> IO ()
1538
setTerminateCallback solver callback = writeIORef (svTerminateCallback solver) (Just callback)
1✔
1539

1540
-- | Clear a callback function set by `setTerminateCallback`
1541
clearTerminateCallback :: Solver -> IO ()
1542
clearTerminateCallback solver = writeIORef (svTerminateCallback solver) Nothing
1✔
1543

1544
-- | Set a callback function used to extract learned clauses from the solver.
1545
-- The solver will call this function for each learned clause.
1546
--
1547
-- See also 'clearLearnCallback' and
1548
-- [IPASIR](https://github.com/biotomas/ipasir)'s @ipasir_set_learn()@ function.
1549
setLearnCallback :: Solver -> (Clause -> IO ()) -> IO ()
1550
setLearnCallback solver callback = writeIORef (svLearnCallback solver) (Just callback)
1✔
1551

1552
-- | Clear a callback function set by `setLearnCallback`
1553
clearLearnCallback :: Solver -> IO ()
1554
clearLearnCallback solver = writeIORef (svLearnCallback solver) Nothing
1✔
1555

1556
{--------------------------------------------------------------------
1557
  API for implementation of @solve@
1558
--------------------------------------------------------------------}
1559

1560
pickBranchLit :: Solver -> IO Lit
1561
pickBranchLit !solver = do
1✔
1562
  gen <- readIORef (svRandomGen solver)
1✔
1563
  let vqueue = svVarQueue solver
1✔
1564
  !randfreq <- configRandomFreq <$> getConfig solver
1✔
1565
  !size <- PQ.queueSize vqueue
1✔
1566
  -- System.Random.random produces [0,1), but System.Random.MWC.uniform produces (0,1]
1567
  !r <- liftM (1 -) $ Rand.uniform gen
1✔
1568
  var <-
1569
    if (r < randfreq && size >= 2) then do
1✔
1570
      a <- PQ.getHeapArray vqueue
1✔
1571
      i <- Rand.uniformR (0, size-1) gen
1✔
1572
      var <- readArray a i
1✔
1573
      val <- varValue solver var
1✔
1574
      if val == lUndef then do
1✔
1575
        modifyIOURef (svNRandomDecision solver) (1+)
1✔
1576
        return var
1✔
1577
      else return litUndef
1✔
1578
    else
1579
      return litUndef
1✔
1580

1581
  -- Activity based decision
1582
  let loop :: IO Var
1583
      loop = do
1✔
1584
        m <- PQ.dequeue vqueue
1✔
1585
        case m of
1✔
1586
          Nothing -> return litUndef
1✔
1587
          Just var2 -> do
1✔
1588
            val2 <- varValue solver var2
1✔
1589
            if val2 /= lUndef
1✔
1590
              then loop
1✔
1591
              else return var2
1✔
1592
  var2 <-
1593
    if var==litUndef
1✔
1594
    then loop
1✔
1595
    else return var
1✔
1596

1597
  if var2==litUndef then
1✔
1598
    return litUndef
1✔
1599
  else do
1✔
1600
    -- TODO: random polarity
1601
    p <- Vec.unsafeRead (svVarPolarity solver) (var2 - 1)
1✔
1602
    return $! literal var2 p
1✔
1603

1604
decide :: Solver -> Lit -> IO ()
1605
decide solver !lit = do
1✔
1606
  modifyIOURef (svNDecision solver) (+1)
1✔
1607
  pushDecisionLevel solver
1✔
1608
  when debugMode $ do
×
1609
    val <- litValue solver lit
×
1610
    when (val /= lUndef) $ error "decide: should not happen"
×
1611
  assign solver lit
1✔
1612
  return ()
×
1613

1614
deduce :: Solver -> IO (Maybe SomeConstraintHandler)
1615
deduce solver = liftM (either Just (const Nothing)) $ runExceptT $ do
1✔
1616
  let loop = do
1✔
1617
        deduceB solver
1✔
1618
        deduceT solver
1✔
1619
        empty <- liftIO $ bcpIsEmpty solver
1✔
1620
        unless empty $ loop
1✔
1621
  loop
1✔
1622

1623
deduceB :: Solver -> ExceptT SomeConstraintHandler IO ()
1624
deduceB solver = loop
1✔
1625
  where
1626
    loop :: ExceptT SomeConstraintHandler IO ()
1627
    loop = do
1✔
1628
      r <- liftIO $ bcpDequeue solver
1✔
1629
      case r of
1✔
1630
        Nothing -> return ()
×
1631
        Just lit -> do
1✔
1632
          processLit lit
1✔
1633
          processVar lit
1✔
1634
          loop
1✔
1635

1636
    processLit :: Lit -> ExceptT SomeConstraintHandler IO ()
1637
    processLit !lit = ExceptT $ liftM (maybe (Right ()) Left) $ do
×
1638
      let falsifiedLit = litNot lit
1✔
1639
          a = svLitWatches solver
1✔
1640
          idx = litIndex falsifiedLit
1✔
1641
      let loop2 [] = return Nothing
1✔
1642
          loop2 (w:ws) = do
1✔
1643
            ok <- propagate solver w falsifiedLit
1✔
1644
            if ok then
1✔
1645
              loop2 ws
1✔
1646
            else do
1✔
1647
              Vec.unsafeModify a idx (++ws)
1✔
1648
              return (Just w)
1✔
1649
      ws <- Vec.unsafeRead a idx
1✔
1650
      Vec.unsafeWrite a idx []
1✔
1651
      loop2 ws
1✔
1652

1653
    processVar :: Lit -> ExceptT SomeConstraintHandler IO ()
1654
    processVar !lit = ExceptT $ liftM (maybe (Right ()) Left) $ do
×
1655
      let falsifiedLit = litNot lit
1✔
1656
          idx = litVar lit - 1
1✔
1657
      let loop2 [] = return Nothing
1✔
1658
          loop2 (w:ws) = do
1✔
1659
            ok <- propagate solver w falsifiedLit
1✔
1660
            if ok
1✔
1661
              then loop2 ws
1✔
1662
              else do
1✔
1663
                Vec.unsafeModify (svVarWatches solver) idx (++ws)
1✔
1664
                return (Just w)
1✔
1665
      ws <- Vec.unsafeRead (svVarWatches solver) idx
1✔
1666
      Vec.unsafeWrite (svVarWatches solver) idx []
1✔
1667
      loop2 ws
1✔
1668

1669
analyzeConflict :: ConstraintHandler c => Solver -> c -> IO (Clause, Level)
1670
analyzeConflict solver constr = do
1✔
1671
  config <- getConfig solver
1✔
1672
  let isHybrid = configLearningStrategy config == LearningHybrid
1✔
1673

1674
  d <- getDecisionLevel solver
1✔
1675
  (out :: Vec.UVec Lit) <- Vec.new
1✔
1676
  Vec.push out 0 -- (leave room for the asserting literal)
1✔
1677
  (pathC :: IOURef Int) <- newIOURef 0
1✔
1678

1679
  pbConstrRef <- newIORef undefined
×
1680

1681
  let f lits = do
1✔
1682
        forM_ lits $ \lit -> do
1✔
1683
          let !v = litVar lit
1✔
1684
          lv <- litLevel solver lit
1✔
1685
          b <- Vec.unsafeRead (svSeen solver) (v - 1)
1✔
1686
          when (not b && lv > levelRoot) $ do
1✔
1687
            varBumpActivity solver v
1✔
1688
            varIncrementParticipated solver v
1✔
1689
            if lv >= d then do
1✔
1690
              Vec.unsafeWrite (svSeen solver) (v - 1) True
1✔
1691
              modifyIOURef pathC (+1)
1✔
1692
            else do
1✔
1693
              Vec.push out lit
1✔
1694

1695
      processLitHybrid pb constr2 lit getLits = do
1✔
1696
        pb2 <- do
1✔
1697
          let clausePB = do
1✔
1698
                lits <- getLits
1✔
1699
                return $ clauseToPBLinAtLeast (lit : lits)
1✔
1700
          b <- isPBRepresentable constr2
1✔
1701
          if not b then do
1✔
1702
            clausePB
1✔
1703
          else do
1✔
1704
            pb2 <- toPBLinAtLeast constr2
1✔
1705
            o <- pbOverSAT solver pb2
1✔
1706
            if o then do
1✔
1707
              clausePB
1✔
1708
            else
1709
              return pb2
1✔
1710
        let pb3 = cutResolve pb pb2 (litVar lit)
1✔
1711
            ls = IS.fromList [l | (_,l) <- fst pb3]
1✔
1712
        seq ls $ writeIORef pbConstrRef (ls, pb3)
1✔
1713

1714
      popUnseen = do
1✔
1715
        l <- peekTrail solver
1✔
1716
        let !v = litVar l
1✔
1717
        b <- Vec.unsafeRead (svSeen solver) (v - 1)
1✔
1718
        if b then do
1✔
1719
          return ()
×
1720
        else do
1✔
1721
          when isHybrid $ do
1✔
1722
            (ls, pb) <- readIORef pbConstrRef
1✔
1723
            when (litNot l `IS.member` ls) $ do
1✔
1724
              Just constr2 <- varReason solver v
1✔
1725
              processLitHybrid pb constr2 l (reasonOf solver constr2 (Just l))
×
1726
          popTrail solver
1✔
1727
          popUnseen
1✔
1728

1729
      loop = do
1✔
1730
        popUnseen
1✔
1731
        l <- peekTrail solver
1✔
1732
        let !v = litVar l
1✔
1733
        Vec.unsafeWrite (svSeen solver) (v - 1) False
1✔
1734
        modifyIOURef pathC (subtract 1)
1✔
1735
        c <- readIOURef pathC
1✔
1736
        if c > 0 then do
1✔
1737
          Just constr2 <- varReason solver v
1✔
1738
          constrBumpActivity solver constr2
1✔
1739
          lits <- reasonOf solver constr2 (Just l)
1✔
1740
          f lits
1✔
1741
          when isHybrid $ do
1✔
1742
            (ls, pb) <- readIORef pbConstrRef
1✔
1743
            when (litNot l `IS.member` ls) $ do
1✔
1744
              processLitHybrid pb constr2 l (return lits)
1✔
1745
          popTrail solver
1✔
1746
          loop
1✔
1747
        else do
1✔
1748
          Vec.unsafeWrite out 0 (litNot l)
1✔
1749

1750
  constrBumpActivity solver constr
1✔
1751
  falsifiedLits <- reasonOf solver constr Nothing
1✔
1752
  f falsifiedLits
1✔
1753
  when isHybrid $ do
1✔
1754
     pb <- do
1✔
1755
       b <- isPBRepresentable constr
1✔
1756
       if b then
1✔
1757
         toPBLinAtLeast constr
1✔
1758
       else
1759
         return (clauseToPBLinAtLeast falsifiedLits)
1✔
1760
     let ls = IS.fromList [l | (_,l) <- fst pb]
1✔
1761
     seq ls $ writeIORef pbConstrRef (ls, pb)
1✔
1762
  loop
1✔
1763
  lits <- liftM IS.fromList $ Vec.getElems out
1✔
1764

1765
  lits2 <- minimizeConflictClause solver lits
1✔
1766

1767
  incrementReasoned solver (IS.toList lits2)
1✔
1768

1769
  xs <- liftM (sortBy (flip (comparing snd))) $
1✔
1770
    forM (IS.toList lits2) $ \l -> do
1✔
1771
      lv <- litLevel solver l
1✔
1772
      return (l,lv)
1✔
1773

1774
  when isHybrid $ do
1✔
1775
    (_, pb) <- readIORef pbConstrRef
1✔
1776
    case pbToClause pb of
1✔
1777
      Just _ -> writeIORef (svPBLearnt solver) Nothing
1✔
1778
      Nothing -> writeIORef (svPBLearnt solver) (Just pb)
1✔
1779

1780
  let level = case xs of
1✔
1781
                [] -> error "analyzeConflict: should not happen"
×
1782
                [_] -> levelRoot
1✔
1783
                _:(_,lv):_ -> lv
1✔
1784
      clause = map fst xs
1✔
1785
  callLearnCallback solver clause
×
1786
  return (clause, level)
1✔
1787

1788
-- { p } ∪ { pにfalseを割り当てる原因のassumption }
1789
analyzeFinal :: Solver -> Lit -> IO [Lit]
1790
analyzeFinal solver p = do
1✔
1791
  let go :: Int -> VarSet -> [Lit] -> IO [Lit]
1792
      go i seen result
1✔
1793
        | i < 0 = return result
1✔
1794
        | otherwise = do
1✔
1795
            l <- Vec.unsafeRead (svTrail solver) i
1✔
1796
            lv <- litLevel solver l
1✔
1797
            if lv == levelRoot then
1✔
1798
              return result
1✔
1799
            else if litVar l `IS.member` seen then do
1✔
1800
              r <- varReason solver (litVar l)
1✔
1801
              case r of
1✔
1802
                Nothing -> do
1✔
1803
                  let seen' = IS.delete (litVar l) seen
1✔
1804
                  go (i-1) seen' (l : result)
1✔
1805
                Just constr  -> do
1✔
1806
                  c <- reasonOf solver constr (Just l)
1✔
1807
                  let seen' = IS.delete (litVar l) seen `IS.union` IS.fromList [litVar l2 | l2 <- c]
1✔
1808
                  go (i-1) seen' result
1✔
1809
            else
1810
              go (i-1) seen result
1✔
1811
  n <- Vec.getSize (svTrail solver)
1✔
1812
  go (n-1) (IS.singleton (litVar p)) [p]
1✔
1813

1814
callLearnCallback :: Solver -> Clause -> IO ()
1815
callLearnCallback solver clause = do
1✔
1816
  cb <- readIORef (svLearnCallback solver)
1✔
1817
  case cb of
1✔
1818
    Nothing -> return ()
×
1819
    Just callback -> callback clause
×
1820

1821
pbBacktrackLevel :: Solver -> PBLinAtLeast -> IO Level
1822
pbBacktrackLevel _ ([], rhs) = assert (rhs > 0) $ return levelRoot
×
1823
pbBacktrackLevel solver (lhs, rhs) = do
1✔
1824
  levelToLiterals <- liftM (IM.unionsWith IM.union) $ forM lhs $ \(c,lit) -> do
1✔
1825
    val <- litValue solver lit
1✔
1826
    if val /= lUndef then do
1✔
1827
      level <- litLevel solver lit
1✔
1828
      return $ IM.singleton level (IM.singleton lit (c,val))
1✔
1829
    else
1830
      return $ IM.singleton maxBound (IM.singleton lit (c,val))
×
1831

1832
  let replay [] !_ = error "pbBacktrackLevel: should not happen"
×
1833
      replay ((lv,lv_lits) : lvs) !slack = do
1✔
1834
        let slack_lv = slack - sum [c | (_,(c,val)) <- IM.toList lv_lits, val == lFalse]
×
1835
        if slack_lv < 0 then
×
1836
          return lv -- CONFLICT
×
1837
        else if any (\(_, lits2) -> any (\(c,_) -> c > slack_lv) (IM.elems lits2)) lvs then
1✔
1838
          return lv -- UNIT
1✔
1839
        else
1840
          replay lvs slack_lv
1✔
1841

1842
  let initial_slack = sum [c | (c,_) <- lhs] - rhs
1✔
1843
  if any (\(c,_) -> c > initial_slack) lhs then
1✔
1844
    return 0
1✔
1845
  else do
1✔
1846
    replay (IM.toList levelToLiterals) initial_slack
1✔
1847

1848
minimizeConflictClause :: Solver -> LitSet -> IO LitSet
1849
minimizeConflictClause solver lits = do
1✔
1850
  ccmin <- configCCMin <$> getConfig solver
1✔
1851
  if ccmin >= 2 then
1✔
1852
    minimizeConflictClauseRecursive solver lits
1✔
1853
  else if ccmin >= 1 then
1✔
1854
    minimizeConflictClauseLocal solver lits
1✔
1855
  else
1856
    return lits
1✔
1857

1858
minimizeConflictClauseLocal :: Solver -> LitSet -> IO LitSet
1859
minimizeConflictClauseLocal solver lits = do
1✔
1860
  let xs = IS.toAscList lits
1✔
1861
  ys <- filterM (liftM not . isRedundant) xs
1✔
1862
  when debugMode $ do
×
1863
    log solver "minimizeConflictClauseLocal:"
×
1864
    log solver $ show xs
×
1865
    log solver $ show ys
×
1866
  return $ IS.fromAscList $ ys
1✔
1867

1868
  where
1869
    isRedundant :: Lit -> IO Bool
1870
    isRedundant lit = do
1✔
1871
      c <- varReason solver (litVar lit)
1✔
1872
      case c of
1✔
1873
        Nothing -> return False
1✔
1874
        Just c2 -> do
1✔
1875
          ls <- reasonOf solver c2 (Just (litNot lit))
×
1876
          allM test ls
1✔
1877

1878
    test :: Lit -> IO Bool
1879
    test lit = do
1✔
1880
      lv <- litLevel solver lit
1✔
1881
      return $ lv == levelRoot || lit `IS.member` lits
1✔
1882

1883
minimizeConflictClauseRecursive :: Solver -> LitSet -> IO LitSet
1884
minimizeConflictClauseRecursive solver lits = do
1✔
1885
  let
1886
    isRedundant :: Lit -> IO Bool
1887
    isRedundant lit = do
1✔
1888
      c <- varReason solver (litVar lit)
1✔
1889
      case c of
1✔
1890
        Nothing -> return False
1✔
1891
        Just c2 -> do
1✔
1892
          ls <- reasonOf solver c2 (Just (litNot lit))
1✔
1893
          go ls IS.empty
1✔
1894

1895
    go :: [Lit] -> IS.IntSet -> IO Bool
1896
    go [] _ = return True
1✔
1897
    go (lit : ls) seen = do
1✔
1898
      lv <- litLevel solver lit
1✔
1899
      if lv == levelRoot || lit `IS.member` lits || lit `IS.member` seen then
1✔
1900
        go ls seen
1✔
1901
      else do
1✔
1902
        c <- varReason solver (litVar lit)
1✔
1903
        case c of
1✔
1904
          Nothing -> return False
1✔
1905
          Just c2 -> do
1✔
1906
            ls2 <- reasonOf solver c2 (Just (litNot lit))
1✔
1907
            go (ls2 ++ ls) (IS.insert lit seen)
1✔
1908

1909
  let xs = IS.toAscList lits
1✔
1910
  ys <- filterM (liftM not . isRedundant) xs
1✔
1911
  when debugMode $ do
×
1912
    log solver "minimizeConflictClauseRecursive:"
×
1913
    log solver $ show xs
×
1914
    log solver $ show ys
×
1915
  return $ IS.fromAscList $ ys
1✔
1916

1917
incrementReasoned :: Solver -> Clause -> IO ()
1918
incrementReasoned solver ls = do
1✔
1919
  let f reasonSided l = do
1✔
1920
        m <- varReason solver (litVar l)
1✔
1921
        case m of
1✔
1922
          Nothing -> return reasonSided
1✔
1923
          Just constr -> do
1✔
1924
            v <- litValue solver l
1✔
1925
            unless (v == lFalse) undefined
×
1926
            xs <- constrReasonOf solver constr (Just (litNot l))
1✔
1927
            return $ reasonSided `IS.union` IS.fromList (map litVar xs)
1✔
1928
  reasonSided <- foldM f IS.empty ls
1✔
1929
  mapM_ (varIncrementReasoned solver) (IS.toList reasonSided)
1✔
1930

1931
peekTrail :: Solver -> IO Lit
1932
peekTrail solver = do
1✔
1933
  n <- Vec.getSize (svTrail solver)
1✔
1934
  Vec.unsafeRead (svTrail solver) (n-1)
1✔
1935

1936
popTrail :: Solver -> IO Lit
1937
popTrail solver = do
1✔
1938
  l <- Vec.unsafePop (svTrail solver)
1✔
1939
  unassign solver (litVar l)
1✔
1940
  return l
×
1941

1942
getDecisionLevel ::Solver -> IO Int
1943
getDecisionLevel solver = Vec.getSize (svTrailLimit solver)
1✔
1944

1945
pushDecisionLevel :: Solver -> IO ()
1946
pushDecisionLevel solver = do
1✔
1947
  Vec.push (svTrailLimit solver) =<< Vec.getSize (svTrail solver)
1✔
1948
  mt <- getTheory solver
1✔
1949
  case mt of
1✔
1950
    Nothing -> return ()
×
1951
    Just t -> thPushBacktrackPoint t
1✔
1952

1953
popDecisionLevel :: Solver -> IO ()
1954
popDecisionLevel solver = do
1✔
1955
  n <- Vec.unsafePop (svTrailLimit solver)
1✔
1956
  let loop = do
1✔
1957
        m <- Vec.getSize (svTrail solver)
1✔
1958
        when (m > n) $ do
1✔
1959
          popTrail solver
1✔
1960
          loop
1✔
1961
  loop
1✔
1962
  mt <- getTheory solver
1✔
1963
  case mt of
1✔
1964
    Nothing -> return ()
×
1965
    Just t -> thPopBacktrackPoint t
1✔
1966

1967
-- | Revert to the state at given level
1968
-- (keeping all assignment at @level@ but not beyond).
1969
backtrackTo :: Solver -> Int -> IO ()
1970
backtrackTo solver level = do
1✔
1971
  when debugMode $ log solver $ printf "backtrackTo: %d" level
×
1972
  loop
1✔
1973
  bcpClear solver
1✔
1974
  mt <- getTheory solver
1✔
1975
  case mt of
1✔
1976
    Nothing -> return ()
×
1977
    Just _ -> do
1✔
1978
      n <- Vec.getSize (svTrail solver)
1✔
1979
      writeIOURef (svTheoryChecked solver) n
1✔
1980
  where
1981
    loop :: IO ()
1982
    loop = do
1✔
1983
      lv <- getDecisionLevel solver
1✔
1984
      when (lv > level) $ do
1✔
1985
        popDecisionLevel solver
1✔
1986
        loop
1✔
1987

1988
constructModel :: Solver -> IO ()
1989
constructModel solver = do
1✔
1990
  n <- getNVars solver
1✔
1991
  (marr::IOUArray Var Bool) <- newArray_ (1,n)
1✔
1992
  forLoop 1 (<=n) (+1) $ \v -> do
1✔
1993
    val <- varValue solver v
1✔
1994
    writeArray marr v (fromJust (unliftBool val))
1✔
1995
  m <- unsafeFreeze marr
1✔
1996
  writeIORef (svModel solver) (Just m)
1✔
1997

1998
saveAssumptionsImplications :: Solver -> IO ()
1999
saveAssumptionsImplications solver = do
1✔
2000
  n <- Vec.getSize (svAssumptions solver)
1✔
2001
  lv <- getDecisionLevel solver
1✔
2002

2003
  lim_beg <-
2004
    if lv == 0 then
1✔
2005
      return 0
1✔
2006
    else
2007
      Vec.read (svTrailLimit solver) 0
1✔
2008
  lim_end <-
2009
    if lv > n then
1✔
2010
       Vec.read (svTrailLimit solver) n
1✔
2011
    else
2012
       Vec.getSize (svTrail solver)
1✔
2013

2014
  let ref = svAssumptionsImplications solver
1✔
2015
  forM_ [lim_beg .. lim_end-1] $ \i -> do
1✔
2016
    lit <- Vec.read (svTrail solver) i
1✔
2017
    modifyIORef' ref (IS.insert lit)
1✔
2018
  forM_ [0..n-1] $ \i -> do
1✔
2019
    lit <- Vec.read (svAssumptions solver) i
1✔
2020
    modifyIORef' ref (IS.delete lit)
1✔
2021

2022
constrDecayActivity :: Solver -> IO ()
2023
constrDecayActivity solver = do
1✔
2024
  d <- configConstrDecay <$> getConfig solver
1✔
2025
  modifyIOURef (svConstrInc solver) (d*)
1✔
2026

2027
constrBumpActivity :: ConstraintHandler a => Solver -> a -> IO ()
2028
constrBumpActivity solver this = do
1✔
2029
  aval <- constrReadActivity this
1✔
2030
  when (aval >= 0) $ do -- learnt clause
1✔
2031
    inc <- readIOURef (svConstrInc solver)
1✔
2032
    let aval2 = aval+inc
1✔
2033
    constrWriteActivity this $! aval2
1✔
2034
    when (aval2 > 1e20) $
1✔
2035
      -- Rescale
2036
      constrRescaleAllActivity solver
×
2037

2038
constrRescaleAllActivity :: Solver -> IO ()
2039
constrRescaleAllActivity solver = do
×
2040
  xs <- learntConstraints solver
×
2041
  forM_ xs $ \c -> do
×
2042
    aval <- constrReadActivity c
×
2043
    when (aval >= 0) $
×
2044
      constrWriteActivity c $! (aval * 1e-20)
×
2045
  modifyIOURef (svConstrInc solver) (* 1e-20)
×
2046

2047
resetStat :: Solver -> IO ()
2048
resetStat solver = do
1✔
2049
  writeIOURef (svNDecision solver) 0
1✔
2050
  writeIOURef (svNRandomDecision solver) 0
1✔
2051
  writeIOURef (svNConflict solver) 0
1✔
2052
  writeIOURef (svNRestart solver) 0
1✔
2053
  writeIOURef (svNLearntGC solver) 0
1✔
2054

2055
printStatHeader :: Solver -> IO ()
2056
printStatHeader solver = do
1✔
2057
  log solver $ "============================[ Search Statistics ]============================"
×
2058
  log solver $ " Time | Restart | Decision | Conflict |      LEARNT     | Fixed    | Removed "
×
2059
  log solver $ "      |         |          |          |    Limit     GC | Var      | Constra "
×
2060
  log solver $ "============================================================================="
×
2061

2062
printStat :: Solver -> Bool -> IO ()
2063
printStat solver force = do
1✔
2064
  nowWC <- getTime Monotonic
1✔
2065
  b <- if force
1✔
2066
       then return True
1✔
2067
       else do
1✔
2068
         lastWC <- readIORef (svLastStatWC solver)
1✔
2069
         return $ sec (nowWC `diffTimeSpec` lastWC) > 1
1✔
2070
  when b $ do
1✔
2071
    startWC   <- readIORef (svStartWC solver)
1✔
2072
    let tm = showTimeDiff $ nowWC `diffTimeSpec` startWC
×
2073
    restart   <- readIOURef (svNRestart solver)
1✔
2074
    dec       <- readIOURef (svNDecision solver)
1✔
2075
    conflict  <- readIOURef (svNConflict solver)
1✔
2076
    learntLim <- readIORef (svLearntLim solver)
1✔
2077
    learntGC  <- readIOURef (svNLearntGC solver)
1✔
2078
    fixed     <- getNFixed solver
1✔
2079
    removed   <- readIOURef (svNRemovedConstr solver)
1✔
2080
    log solver $ printf "%s | %7d | %8d | %8d | %8d %6d | %8d | %8d"
×
2081
      tm restart dec conflict learntLim learntGC fixed removed
×
2082
    writeIORef (svLastStatWC solver) nowWC
1✔
2083

2084
showTimeDiff :: TimeSpec -> String
2085
showTimeDiff t
×
2086
  | si <  100  = printf "%4.1fs" (fromRational s :: Double)
×
2087
  | si <= 9999 = printf "%4ds" si
×
2088
  | mi <  100  = printf "%4.1fm" (fromRational m :: Double)
×
2089
  | mi <= 9999 = printf "%4dm" mi
×
2090
  | hi <  100  = printf "%4.1fs" (fromRational h :: Double)
×
2091
  | otherwise  = printf "%4dh" hi
×
2092
  where
2093
    s :: Rational
2094
    s = fromIntegral (toNanoSecs t) / 10^(9::Int)
×
2095

2096
    si :: Integer
2097
    si = fromIntegral (sec t)
×
2098

2099
    m :: Rational
2100
    m = s / 60
×
2101

2102
    mi :: Integer
2103
    mi = round m
×
2104

2105
    h :: Rational
2106
    h = m / 60
×
2107

2108
    hi :: Integer
2109
    hi = round h
×
2110

2111
{--------------------------------------------------------------------
2112
  constraint implementation
2113
--------------------------------------------------------------------}
2114

2115
class (Eq a, Hashable a) => ConstraintHandler a where
2116
  toConstraintHandler :: a -> SomeConstraintHandler
2117

2118
  showConstraintHandler :: a -> IO String
2119

2120
  constrAttach :: Solver -> SomeConstraintHandler -> a -> IO Bool
2121

2122
  constrDetach :: Solver -> SomeConstraintHandler -> a -> IO ()
2123

2124
  constrIsLocked :: Solver -> SomeConstraintHandler -> a -> IO Bool
2125

2126
  -- | invoked with the watched literal when the literal is falsified.
2127
  -- 'watch' で 'toConstraint' を呼び出して heap allocation が発生するのを
2128
  -- 避けるために、元の 'SomeConstraintHandler' も渡しておく。
2129
  constrPropagate :: Solver -> SomeConstraintHandler -> a -> Lit -> IO Bool
2130

2131
  -- | deduce a clause C∨l from the constraint and return C.
2132
  -- C and l should be false and true respectively under the current
2133
  -- assignment.
2134
  constrReasonOf :: Solver -> a -> Maybe Lit -> IO Clause
2135

2136
  constrOnUnassigned :: Solver -> SomeConstraintHandler -> a -> Lit -> IO ()
2137

2138
  isPBRepresentable :: a -> IO Bool
2139
  toPBLinAtLeast :: a -> IO PBLinAtLeast
2140

2141
  isSatisfied :: Solver -> a -> IO Bool
2142

2143
  constrIsProtected :: Solver -> a -> IO Bool
2144
  constrIsProtected _ _ = return False
×
2145

2146
  constrWeight :: Solver -> a -> IO Double
2147
  constrWeight _ _ = return 1.0
1✔
2148

2149
  constrReadActivity :: a -> IO Double
2150

2151
  constrWriteActivity :: a -> Double -> IO ()
2152

2153
attach :: Solver -> SomeConstraintHandler -> IO Bool
2154
attach solver c = constrAttach solver c c
1✔
2155

2156
detach :: Solver -> SomeConstraintHandler -> IO ()
2157
detach solver c = do
1✔
2158
  constrDetach solver c c
1✔
2159
  b <- isPBRepresentable c
1✔
2160
  when b $ do
1✔
2161
    (lhs,_) <- toPBLinAtLeast c
1✔
2162
    forM_ lhs $ \(_,lit) -> do
1✔
2163
      Vec.unsafeModify (svLitOccurList solver) (litIndex lit) (HashSet.delete c)
1✔
2164

2165
-- | invoked with the watched literal when the literal is falsified.
2166
propagate :: Solver -> SomeConstraintHandler -> Lit -> IO Bool
2167
propagate solver c l = constrPropagate solver c c l
1✔
2168

2169
-- | deduce a clause C∨l from the constraint and return C.
2170
-- C and l should be false and true respectively under the current
2171
-- assignment.
2172
reasonOf :: ConstraintHandler a => Solver -> a -> Maybe Lit -> IO Clause
2173
reasonOf solver c x = do
1✔
2174
  when debugMode $
1✔
2175
    case x of
×
2176
      Nothing -> return ()
×
2177
      Just lit -> do
×
2178
        val <- litValue solver lit
×
2179
        unless (lTrue == val) $ do
×
2180
          str <- showConstraintHandler c
×
2181
          error (printf "reasonOf: value of literal %d should be True but %s (constrReasonOf %s %s)" lit (show val) str (show x))
×
2182
  cl <- constrReasonOf solver c x
1✔
2183
  when debugMode $ do
×
2184
    forM_ cl $ \lit -> do
×
2185
      val <- litValue solver lit
×
2186
      unless (lFalse == val) $ do
×
2187
        str <- showConstraintHandler c
×
2188
        error (printf "reasonOf: value of literal %d should be False but %s (constrReasonOf %s %s)" lit (show val) str (show x))
×
2189
  return cl
1✔
2190

2191
isLocked :: Solver -> SomeConstraintHandler -> IO Bool
2192
isLocked solver c = constrIsLocked solver c c
1✔
2193

2194
data SomeConstraintHandler
2195
  = CHClause !ClauseHandler
2196
  | CHAtLeast !AtLeastHandler
2197
  | CHPBCounter !PBHandlerCounter
2198
  | CHPBPueblo !PBHandlerPueblo
2199
  | CHXORClause !XORClauseHandler
2200
  | CHTheory !TheoryHandler
2201
  deriving Eq
1✔
2202

2203
instance Hashable SomeConstraintHandler where
2204
  hashWithSalt s (CHClause c)    = s `hashWithSalt` (0::Int) `hashWithSalt` c
1✔
2205
  hashWithSalt s (CHAtLeast c)   = s `hashWithSalt` (1::Int) `hashWithSalt` c
×
2206
  hashWithSalt s (CHPBCounter c) = s `hashWithSalt` (2::Int) `hashWithSalt` c
1✔
2207
  hashWithSalt s (CHPBPueblo c)  = s `hashWithSalt` (3::Int) `hashWithSalt` c
1✔
2208
  hashWithSalt s (CHXORClause c) = s `hashWithSalt` (4::Int) `hashWithSalt` c
×
2209
  hashWithSalt s (CHTheory c)    = s `hashWithSalt` (5::Int) `hashWithSalt` c
×
2210

2211
instance ConstraintHandler SomeConstraintHandler where
2212
  toConstraintHandler = id
1✔
2213

2214
  showConstraintHandler (CHClause c)    = showConstraintHandler c
×
2215
  showConstraintHandler (CHAtLeast c)   = showConstraintHandler c
×
2216
  showConstraintHandler (CHPBCounter c) = showConstraintHandler c
×
2217
  showConstraintHandler (CHPBPueblo c)  = showConstraintHandler c
×
2218
  showConstraintHandler (CHXORClause c) = showConstraintHandler c
×
2219
  showConstraintHandler (CHTheory c)    = showConstraintHandler c
×
2220

2221
  constrAttach solver this (CHClause c)    = constrAttach solver this c
×
2222
  constrAttach solver this (CHAtLeast c)   = constrAttach solver this c
×
2223
  constrAttach solver this (CHPBCounter c) = constrAttach solver this c
1✔
2224
  constrAttach solver this (CHPBPueblo c)  = constrAttach solver this c
1✔
2225
  constrAttach solver this (CHXORClause c) = constrAttach solver this c
×
2226
  constrAttach solver this (CHTheory c)    = constrAttach solver this c
×
2227

2228
  constrDetach solver this (CHClause c)    = constrDetach solver this c
1✔
2229
  constrDetach solver this (CHAtLeast c)   = constrDetach solver this c
×
2230
  constrDetach solver this (CHPBCounter c) = constrDetach solver this c
1✔
2231
  constrDetach solver this (CHPBPueblo c)  = constrDetach solver this c
×
2232
  constrDetach solver this (CHXORClause c) = constrDetach solver this c
×
2233
  constrDetach solver this (CHTheory c)    = constrDetach solver this c
×
2234

2235
  constrIsLocked solver this (CHClause c)    = constrIsLocked solver this c
1✔
2236
  constrIsLocked solver this (CHAtLeast c)   = constrIsLocked solver this c
×
2237
  constrIsLocked solver this (CHPBCounter c) = constrIsLocked solver this c
×
2238
  constrIsLocked solver this (CHPBPueblo c)  = constrIsLocked solver this c
×
2239
  constrIsLocked solver this (CHXORClause c) = constrIsLocked solver this c
×
2240
  constrIsLocked solver this (CHTheory c)    = constrIsLocked solver this c
×
2241

2242
  constrPropagate solver this (CHClause c)  lit   = constrPropagate solver this c lit
1✔
2243
  constrPropagate solver this (CHAtLeast c) lit   = constrPropagate solver this c lit
1✔
2244
  constrPropagate solver this (CHPBCounter c) lit = constrPropagate solver this c lit
1✔
2245
  constrPropagate solver this (CHPBPueblo c) lit  = constrPropagate solver this c lit
1✔
2246
  constrPropagate solver this (CHXORClause c) lit = constrPropagate solver this c lit
1✔
2247
  constrPropagate solver this (CHTheory c) lit    = constrPropagate solver this c lit
×
2248

2249
  constrReasonOf solver (CHClause c)  l   = constrReasonOf solver c l
×
2250
  constrReasonOf solver (CHAtLeast c) l   = constrReasonOf solver c l
1✔
2251
  constrReasonOf solver (CHPBCounter c) l = constrReasonOf solver c l
1✔
2252
  constrReasonOf solver (CHPBPueblo c) l  = constrReasonOf solver c l
1✔
2253
  constrReasonOf solver (CHXORClause c) l = constrReasonOf solver c l
1✔
2254
  constrReasonOf solver (CHTheory c) l    = constrReasonOf solver c l
×
2255

2256
  constrOnUnassigned solver this (CHClause c)  l   = constrOnUnassigned solver this c l
×
2257
  constrOnUnassigned solver this (CHAtLeast c) l   = constrOnUnassigned solver this c l
×
2258
  constrOnUnassigned solver this (CHPBCounter c) l = constrOnUnassigned solver this c l
×
2259
  constrOnUnassigned solver this (CHPBPueblo c) l  = constrOnUnassigned solver this c l
1✔
2260
  constrOnUnassigned solver this (CHXORClause c) l = constrOnUnassigned solver this c l
×
2261
  constrOnUnassigned solver this (CHTheory c) l    = constrOnUnassigned solver this c l
×
2262

2263
  isPBRepresentable (CHClause c)    = isPBRepresentable c
×
2264
  isPBRepresentable (CHAtLeast c)   = isPBRepresentable c
×
2265
  isPBRepresentable (CHPBCounter c) = isPBRepresentable c
×
2266
  isPBRepresentable (CHPBPueblo c)  = isPBRepresentable c
×
2267
  isPBRepresentable (CHXORClause c) = isPBRepresentable c
×
2268
  isPBRepresentable (CHTheory c)    = isPBRepresentable c
×
2269

2270
  toPBLinAtLeast (CHClause c)    = toPBLinAtLeast c
1✔
2271
  toPBLinAtLeast (CHAtLeast c)   = toPBLinAtLeast c
1✔
2272
  toPBLinAtLeast (CHPBCounter c) = toPBLinAtLeast c
1✔
2273
  toPBLinAtLeast (CHPBPueblo c)  = toPBLinAtLeast c
1✔
2274
  toPBLinAtLeast (CHXORClause c) = toPBLinAtLeast c
×
2275
  toPBLinAtLeast (CHTheory c)    = toPBLinAtLeast c
×
2276

2277
  isSatisfied solver (CHClause c)    = isSatisfied solver c
1✔
2278
  isSatisfied solver (CHAtLeast c)   = isSatisfied solver c
1✔
2279
  isSatisfied solver (CHPBCounter c) = isSatisfied solver c
1✔
2280
  isSatisfied solver (CHPBPueblo c)  = isSatisfied solver c
1✔
2281
  isSatisfied solver (CHXORClause c) = isSatisfied solver c
1✔
2282
  isSatisfied solver (CHTheory c)    = isSatisfied solver c
×
2283

2284
  constrIsProtected solver (CHClause c)    = constrIsProtected solver c
×
2285
  constrIsProtected solver (CHAtLeast c)   = constrIsProtected solver c
×
2286
  constrIsProtected solver (CHPBCounter c) = constrIsProtected solver c
×
2287
  constrIsProtected solver (CHPBPueblo c)  = constrIsProtected solver c
×
2288
  constrIsProtected solver (CHXORClause c) = constrIsProtected solver c
×
2289
  constrIsProtected solver (CHTheory c)    = constrIsProtected solver c
×
2290

2291
  constrReadActivity (CHClause c)    = constrReadActivity c
1✔
2292
  constrReadActivity (CHAtLeast c)   = constrReadActivity c
1✔
2293
  constrReadActivity (CHPBCounter c) = constrReadActivity c
1✔
2294
  constrReadActivity (CHPBPueblo c)  = constrReadActivity c
1✔
2295
  constrReadActivity (CHXORClause c) = constrReadActivity c
1✔
2296
  constrReadActivity (CHTheory c)    = constrReadActivity c
×
2297

2298
  constrWriteActivity (CHClause c)    aval = constrWriteActivity c aval
1✔
2299
  constrWriteActivity (CHAtLeast c)   aval = constrWriteActivity c aval
1✔
2300
  constrWriteActivity (CHPBCounter c) aval = constrWriteActivity c aval
1✔
2301
  constrWriteActivity (CHPBPueblo c)  aval = constrWriteActivity c aval
×
2302
  constrWriteActivity (CHXORClause c) aval = constrWriteActivity c aval
×
2303
  constrWriteActivity (CHTheory c)    aval = constrWriteActivity c aval
×
2304

2305
isReasonOf :: Solver -> SomeConstraintHandler -> Lit -> IO Bool
2306
isReasonOf solver c lit = do
1✔
2307
  val <- litValue solver lit
1✔
2308
  if val == lUndef then
1✔
2309
    return False
1✔
2310
  else do
1✔
2311
    m <- varReason solver (litVar lit)
1✔
2312
    case m of
1✔
2313
      Nothing -> return False
1✔
2314
      Just c2  -> return $! c == c2
1✔
2315

2316
-- To avoid heap-allocation Maybe value, it returns -1 when not found.
2317
findForWatch :: Solver -> LitArray -> Int -> Int -> IO Int
2318
#ifndef __GLASGOW_HASKELL__
2319
findForWatch solver a beg end = go beg end
2320
  where
2321
    go :: Int -> Int -> IO Int
2322
    go i end | i > end = return (-1)
2323
    go i end = do
2324
      val <- litValue s =<< readLitArray a i
2325
      if val /= lFalse
2326
        then return i
2327
        else go (i+1) end
2328
#else
2329
{- We performed worker-wrapper transfomation manually, since the worker
2330
   generated by GHC has type
2331
   "Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int #)",
2332
   not "Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #)".
2333
   We want latter one to avoid heap-allocating Int value. -}
2334
findForWatch solver a (I# beg) (I# end) = IO $ \w ->
1✔
2335
  case go# beg end w of
1✔
2336
    (# w2, ret #) -> (# w2, I# ret #)
1✔
2337
  where
2338
    go# :: Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #)
2339
    go# i end' w | isTrue# (i ># end') = (# w, -1# #)
1✔
2340
    go# i end' w =
2341
      case unIO (litValue solver =<< readLitArray a (I# i)) w of
1✔
2342
        (# w2, val #) ->
2343
          if val /= lFalse
1✔
2344
            then (# w2, i #)
1✔
2345
            else go# (i +# 1#) end' w2
1✔
2346

2347
    unIO (IO f) = f
1✔
2348
#endif
2349

2350
-- To avoid heap-allocating Maybe value, it returns -1 when not found.
2351
findForWatch2 :: Solver -> LitArray -> Int -> Int -> IO Int
2352
#ifndef __GLASGOW_HASKELL__
2353
findForWatch2 solver a beg end = go beg end
2354
  where
2355
    go :: Int -> Int -> IO Int
2356
    go i end | i > end = return (-1)
2357
    go i end = do
2358
      val <- litValue s =<< readLitArray a i
2359
      if val == lUndef
2360
        then return i
2361
        else go (i+1) end
2362
#else
2363
{- We performed worker-wrapper transfomation manually, since the worker
2364
   generated by GHC has type
2365
   "Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int #)",
2366
   not "Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #)".
2367
   We want latter one to avoid heap-allocating Int value. -}
2368
findForWatch2 solver a (I# beg) (I# end) = IO $ \w ->
1✔
2369
  case go# beg end w of
1✔
2370
    (# w2, ret #) -> (# w2, I# ret #)
1✔
2371
  where
2372
    go# :: Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #)
2373
    go# i end w | isTrue# (i ># end) = (# w, -1# #)
1✔
2374
    go# i end w =
2375
      case unIO (litValue solver =<< readLitArray a (I# i)) w of
1✔
2376
        (# w2, val #) ->
2377
          if val == lUndef
1✔
2378
            then (# w2, i #)
1✔
2379
            else go# (i +# 1#) end w2
1✔
2380

2381
    unIO (IO f) = f
1✔
2382
#endif
2383

2384
{--------------------------------------------------------------------
2385
  Clause
2386
--------------------------------------------------------------------}
2387

2388
data ClauseHandler
2389
  = ClauseHandler
2390
  { claLits :: !LitArray
1✔
2391
  , claActivity :: !(IORef Double)
1✔
2392
  , claHash :: !Int
1✔
2393
  }
2394

2395
claGetSize :: ClauseHandler -> IO Int
2396
claGetSize cla = getLitArraySize (claLits cla)
1✔
2397

2398
instance Eq ClauseHandler where
2399
  (==) = (==) `on` claLits
1✔
2400

2401
instance Hashable ClauseHandler where
2402
  hash = claHash
1✔
2403
  hashWithSalt = defaultHashWithSalt
1✔
2404

2405
newClauseHandler :: Clause -> Bool -> IO ClauseHandler
2406
newClauseHandler ls learnt = do
1✔
2407
  a <- newLitArray ls
1✔
2408
  act <- newIORef $! (if learnt then 0 else -1)
1✔
2409
  return (ClauseHandler a act (hash ls))
1✔
2410

2411
instance ConstraintHandler ClauseHandler where
2412
  toConstraintHandler = CHClause
1✔
2413

2414
  showConstraintHandler this = do
×
2415
    lits <- getLits (claLits this)
×
2416
    return (show lits)
×
2417

2418
  constrAttach solver this this2 = do
×
2419
    -- BCP Queue should be empty at this point.
2420
    -- If not, duplicated propagation happens.
2421
    bcpCheckEmpty solver
×
2422

2423
    size <- claGetSize this2
×
2424
    if size == 0 then do
×
2425
      markBad solver
×
2426
      return False
×
2427
    else if size == 1 then do
×
2428
      lit0 <- readLitArray (claLits this2) 0
×
2429
      assignBy solver lit0 this
×
2430
    else do
×
2431
      ref <- newIORef 1
×
2432
      let f i = do
×
2433
            lit_i <- readLitArray (claLits this2) i
×
2434
            val_i <- litValue solver lit_i
×
2435
            if val_i /= lFalse then
×
2436
              return True
×
2437
            else do
×
2438
              j <- readIORef ref
×
2439
              k <- findForWatch solver (claLits this2) j (size - 1)
×
2440
              case k of
×
2441
                -1 -> do
×
2442
                  return False
×
2443
                _ -> do
×
2444
                  lit_k <- readLitArray (claLits this2) k
×
2445
                  writeLitArray (claLits this2) i lit_k
×
2446
                  writeLitArray (claLits this2) k lit_i
×
2447
                  writeIORef ref $! (k+1)
×
2448
                  return True
×
2449

2450
      b <- f 0
×
2451
      if b then do
×
2452
        lit0 <- readLitArray (claLits this2) 0
×
2453
        watchLit solver lit0 this
×
2454
        b2 <- f 1
×
2455
        if b2 then do
×
2456
          lit1 <- readLitArray (claLits this2) 1
×
2457
          watchLit solver lit1 this
×
2458
          return True
×
2459
        else do -- UNIT
×
2460
          -- We need to watch the most recently falsified literal
2461
          (i,_) <- liftM (maximumBy (comparing snd)) $ forM [1..size-1] $ \l -> do
×
2462
            lit <- readLitArray (claLits this2) l
×
2463
            lv <- litLevel solver lit
×
2464
            return (l,lv)
×
2465
          lit1 <- readLitArray (claLits this2) 1
×
2466
          liti <- readLitArray (claLits this2) i
×
2467
          writeLitArray (claLits this2) 1 liti
×
2468
          writeLitArray (claLits this2) i lit1
×
2469
          watchLit solver liti this
×
2470
          assignBy solver lit0 this -- should always succeed
×
2471
      else do -- CONFLICT
×
2472
        ls <- liftM (map fst . sortBy (flip (comparing snd))) $ forM [0..size-1] $ \l -> do
×
2473
          lit <- readLitArray (claLits this2) l
×
2474
          lv <- litLevel solver lit
×
2475
          return (l,lv)
×
2476
        forM_ (zip [0..] ls) $ \(i,lit) -> do
×
2477
          writeLitArray (claLits this2) i lit
×
2478
        lit0 <- readLitArray (claLits this2) 0
×
2479
        lit1 <- readLitArray (claLits this2) 1
×
2480
        watchLit solver lit0 this
×
2481
        watchLit solver lit1 this
×
2482
        return False
×
2483

2484
  constrDetach solver this this2 = do
1✔
2485
    size <- claGetSize this2
1✔
2486
    when (size >= 2) $ do
1✔
2487
      lit0 <- readLitArray (claLits this2) 0
1✔
2488
      lit1 <- readLitArray (claLits this2) 1
1✔
2489
      unwatchLit solver lit0 this
1✔
2490
      unwatchLit solver lit1 this
1✔
2491

2492
  constrIsLocked solver this this2 = do
1✔
2493
    size <- claGetSize this2
1✔
2494
    if size < 2 then
×
2495
      return False
×
2496
    else do
1✔
2497
      lit <- readLitArray (claLits this2) 0
1✔
2498
      isReasonOf solver this lit
1✔
2499

2500
  constrPropagate !solver this this2 !falsifiedLit = do
1✔
2501
    preprocess
1✔
2502

2503
    !lit0 <- readLitArray a 0
1✔
2504
    !val0 <- litValue solver lit0
1✔
2505
    if val0 == lTrue then do
1✔
2506
      watchLit solver falsifiedLit this
1✔
2507
      return True
1✔
2508
    else do
1✔
2509
      size <- claGetSize this2
1✔
2510
      i <- findForWatch solver a 2 (size - 1)
1✔
2511
      case i of
1✔
2512
        -1 -> do
1✔
2513
          when debugMode $ logIO solver $ do
×
2514
             str <- showConstraintHandler this
×
2515
             return $ printf "constrPropagate: %s is unit" str
×
2516
          watchLit solver falsifiedLit this
1✔
2517
          assignBy solver lit0 this
1✔
2518
        _  -> do
1✔
2519
          !lit1 <- readLitArray a 1
1✔
2520
          !liti <- readLitArray a i
1✔
2521
          writeLitArray a 1 liti
1✔
2522
          writeLitArray a i lit1
1✔
2523
          watchLit solver liti this
1✔
2524
          return True
1✔
2525

2526
    where
2527
      a = claLits this2
1✔
2528

2529
      preprocess :: IO ()
2530
      preprocess = do
1✔
2531
        !l0 <- readLitArray a 0
1✔
2532
        !l1 <- readLitArray a 1
1✔
2533
        assert (l0==falsifiedLit || l1==falsifiedLit) $ return ()
×
2534
        when (l0==falsifiedLit) $ do
1✔
2535
          writeLitArray a 0 l1
1✔
2536
          writeLitArray a 1 l0
1✔
2537

2538
  constrReasonOf _ this l = do
1✔
2539
    lits <- getLits (claLits this)
1✔
2540
    case l of
1✔
2541
      Nothing -> return lits
1✔
2542
      Just lit -> do
1✔
2543
        assert (lit == head lits) $ return ()
×
2544
        return $ tail lits
1✔
2545

2546
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2547

2548
  isPBRepresentable _ = return True
1✔
2549

2550
  toPBLinAtLeast this = do
1✔
2551
    lits <- getLits (claLits this)
1✔
2552
    return ([(1,l) | l <- lits], 1)
1✔
2553

2554
  isSatisfied solver this = do
1✔
2555
    n <- getLitArraySize (claLits this)
1✔
2556
    liftM isLeft $ runExceptT $ forLoop 0 (<n) (+1) $ \i -> do
1✔
2557
      v <- lift $ litValue solver =<< readLitArray (claLits this) i
1✔
2558
      when (v == lTrue) $ throwE ()
×
2559

2560
  constrIsProtected _ this = do
1✔
2561
    size <- claGetSize this
1✔
2562
    return $! size <= 2
1✔
2563

2564
  constrReadActivity this = readIORef (claActivity this)
1✔
2565

2566
  constrWriteActivity this aval = writeIORef (claActivity this) $! aval
1✔
2567

2568
basicAttachClauseHandler :: Solver -> ClauseHandler -> IO Bool
2569
basicAttachClauseHandler solver this = do
1✔
2570
  let constr = toConstraintHandler this
1✔
2571
  lits <- getLits (claLits this)
1✔
2572
  case lits of
1✔
2573
    [] -> do
×
2574
      markBad solver
×
2575
      return False
×
2576
    [l1] -> do
×
2577
      assignBy solver l1 constr
×
2578
    l1:l2:_ -> do
1✔
2579
      watchLit solver l1 constr
1✔
2580
      watchLit solver l2 constr
1✔
2581
      return True
×
2582

2583
{--------------------------------------------------------------------
2584
  Cardinality Constraint
2585
--------------------------------------------------------------------}
2586

2587
data AtLeastHandler
2588
  = AtLeastHandler
2589
  { atLeastLits :: !LitArray
1✔
2590
  , atLeastNum :: !Int
1✔
2591
  , atLeastActivity :: !(IORef Double)
1✔
2592
  , atLeastHash :: !Int
×
2593
  }
2594

2595
instance Eq AtLeastHandler where
2596
  (==) = (==) `on` atLeastLits
×
2597

2598
instance Hashable AtLeastHandler where
2599
  hash = atLeastHash
×
2600
  hashWithSalt = defaultHashWithSalt
×
2601

2602
newAtLeastHandler :: [Lit] -> Int -> Bool -> IO AtLeastHandler
2603
newAtLeastHandler ls n learnt = do
1✔
2604
  a <- newLitArray ls
1✔
2605
  act <- newIORef $! (if learnt then 0 else -1)
1✔
2606
  return (AtLeastHandler a n act (hash (ls,n)))
1✔
2607

2608
instance ConstraintHandler AtLeastHandler where
2609
  toConstraintHandler = CHAtLeast
1✔
2610

2611
  showConstraintHandler this = do
×
2612
    lits <- getLits (atLeastLits this)
×
2613
    return $ show lits ++ " >= " ++ show (atLeastNum this)
×
2614

2615
  -- FIXME: simplify implementation
2616
  constrAttach solver this this2 = do
1✔
2617
    -- BCP Queue should be empty at this point.
2618
    -- If not, duplicated propagation happens.
2619
    bcpCheckEmpty solver
1✔
2620

2621
    let a = atLeastLits this2
1✔
2622
    m <- getLitArraySize a
1✔
2623
    let n = atLeastNum this2
1✔
2624

2625
    if m < n then do
×
2626
      markBad solver
×
2627
      return False
×
2628
    else if m == n then do
×
2629
      let f i = do
×
2630
            lit <- readLitArray a i
×
2631
            assignBy solver lit this
×
2632
      allM f [0..n-1]
×
2633
    else do -- m > n
1✔
2634
      let f !i !j
1✔
2635
            | i == n = do
1✔
2636
                -- NOT VIOLATED: n literals (0 .. n-1) are watched
2637
                k <- findForWatch solver a j (m - 1)
×
2638
                if k /= -1 then do
×
2639
                  -- NOT UNIT
2640
                  lit_n <- readLitArray a n
×
2641
                  lit_k <- readLitArray a k
×
2642
                  writeLitArray a n lit_k
×
2643
                  writeLitArray a k lit_n
×
2644
                  watchLit solver lit_k this
×
2645
                  -- n+1 literals (0 .. n) are watched.
2646
                else do
1✔
2647
                  -- UNIT
2648
                  forLoop 0 (<n) (+1) $ \l -> do
1✔
2649
                    lit <- readLitArray a l
1✔
2650
                    _ <- assignBy solver lit this -- should always succeed
×
2651
                    return ()
×
2652
                  -- We need to watch the most recently falsified literal
2653
                  (l,_) <- liftM (maximumBy (comparing snd)) $ forM [n..m-1] $ \l -> do
1✔
2654
                    lit <- readLitArray a l
1✔
2655
                    lv <- litLevel solver lit
1✔
2656
                    when debugMode $ do
×
2657
                      val <- litValue solver lit
×
2658
                      unless (val == lFalse) $ error "AtLeastHandler.attach: should not happen"
×
2659
                    return (l,lv)
1✔
2660
                  lit_n <- readLitArray a n
1✔
2661
                  lit_l <- readLitArray a l
1✔
2662
                  writeLitArray a n lit_l
1✔
2663
                  writeLitArray a l lit_n
1✔
2664
                  watchLit solver lit_l this
×
2665
                  -- n+1 literals (0 .. n) are watched.
2666
                return True
1✔
2667
            | otherwise = do
1✔
2668
                assert (i < n && n <= j) $ return ()
×
2669
                lit_i <- readLitArray a i
1✔
2670
                val_i <- litValue solver lit_i
1✔
2671
                if val_i /= lFalse then do
1✔
2672
                  watchLit solver lit_i this
×
2673
                  f (i+1) j
1✔
2674
                else do
1✔
2675
                  k <- findForWatch solver a j (m - 1)
1✔
2676
                  if k /= -1 then do
×
2677
                    lit_k <- readLitArray a k
1✔
2678
                    writeLitArray a i lit_k
1✔
2679
                    writeLitArray a k lit_i
1✔
2680
                    watchLit solver lit_k this
×
2681
                    f (i+1) (k+1)
1✔
2682
                  else do
×
2683
                    -- CONFLICT
2684
                    -- We need to watch unassigned literals or most recently falsified literals.
2685
                    do xs <- liftM (sortBy (flip (comparing snd))) $ forM [i..m-1] $ \l -> do
×
2686
                         lit <- readLitArray a l
×
2687
                         val <- litValue solver lit
×
2688
                         if val == lFalse then do
×
2689
                           lv <- litLevel solver lit
×
2690
                           return (lit, lv)
×
2691
                         else do
×
2692
                           return (lit, maxBound)
×
2693
                       forM_ (zip [i..m-1] xs) $ \(l,(lit,_lv)) -> do
×
2694
                         writeLitArray a l lit
×
2695
                    forLoop i (<=n) (+1) $ \l -> do
×
2696
                      lit_l <- readLitArray a l
×
2697
                      watchLit solver lit_l this
×
2698
                    -- n+1 literals (0 .. n) are watched.
2699
                    return False
×
2700
      f 0 n
1✔
2701

2702
  constrDetach solver this this2 = do
1✔
2703
    lits <- getLits (atLeastLits this2)
1✔
2704
    let n = atLeastNum this2
1✔
2705
    when (length lits > n) $ do
1✔
2706
      forLoop 0 (<=n) (+1) $ \i -> do
1✔
2707
        lit <- readLitArray (atLeastLits this2) i
1✔
2708
        unwatchLit solver lit this
×
2709

2710
  constrIsLocked solver this this2 = do
1✔
2711
    size <- getLitArraySize (atLeastLits this2)
1✔
2712
    let n = atLeastNum this2
1✔
2713
        loop i
1✔
2714
          | i > n = return False
1✔
2715
          | otherwise = do
1✔
2716
              l <- readLitArray (atLeastLits this2) i
1✔
2717
              b <- isReasonOf solver this l
×
2718
              if b then return True else loop (i+1)
×
2719
    if size >= n+1 then
×
2720
      loop 0
1✔
2721
    else
2722
      return False
×
2723

2724
  constrPropagate solver this this2 falsifiedLit = do
1✔
2725
    preprocess
1✔
2726

2727
    when debugMode $ do
×
2728
      litn <- readLitArray a n
×
2729
      unless (litn == falsifiedLit) $ error "AtLeastHandler.constrPropagate: should not happen"
×
2730

2731
    m <- getLitArraySize a
1✔
2732
    i <- findForWatch solver a (n+1) (m-1)
1✔
2733
    case i of
1✔
2734
      -1 -> do
1✔
2735
        when debugMode $ logIO solver $ do
×
2736
          str <- showConstraintHandler this
×
2737
          return $ printf "constrPropagate: %s is unit" str
×
2738
        watchLit solver falsifiedLit this
1✔
2739
        let loop :: Int -> IO Bool
2740
            loop j
1✔
2741
              | j >= n = return True
1✔
2742
              | otherwise = do
1✔
2743
                  litj <- readLitArray a j
1✔
2744
                  ret2 <- assignBy solver litj this
1✔
2745
                  if ret2
1✔
2746
                    then loop (j+1)
1✔
2747
                    else return False
1✔
2748
        loop 0
1✔
2749
      _ -> do
1✔
2750
        liti <- readLitArray a i
1✔
2751
        litn <- readLitArray a n
1✔
2752
        writeLitArray a i litn
1✔
2753
        writeLitArray a n liti
1✔
2754
        watchLit solver liti this
×
2755
        return True
1✔
2756

2757
    where
2758
      a = atLeastLits this2
1✔
2759
      n = atLeastNum this2
1✔
2760

2761
      preprocess :: IO ()
2762
      preprocess = loop 0
1✔
2763
        where
2764
          loop :: Int -> IO ()
2765
          loop i
1✔
2766
            | i >= n = return ()
×
2767
            | otherwise = do
1✔
2768
              li <- readLitArray a i
1✔
2769
              if (li /= falsifiedLit) then
1✔
2770
                loop (i+1)
1✔
2771
              else do
1✔
2772
                ln <- readLitArray a n
1✔
2773
                writeLitArray a n li
1✔
2774
                writeLitArray a i ln
1✔
2775

2776
  constrReasonOf solver this concl = do
1✔
2777
    m <- getLitArraySize (atLeastLits this)
1✔
2778
    let n = atLeastNum this
1✔
2779
    falsifiedLits <- mapM (readLitArray (atLeastLits this)) [n..m-1] -- drop first n elements
1✔
2780
    when debugMode $ do
×
2781
      forM_ falsifiedLits $ \lit -> do
×
2782
        val <- litValue solver lit
×
2783
        unless (val == lFalse) $ do
×
2784
          error $ printf "AtLeastHandler.constrReasonOf: %d is %s (lFalse expected)" lit (show val)
×
2785
    case concl of
1✔
2786
      Nothing -> do
1✔
2787
        let go :: Int -> IO Lit
2788
            go i
1✔
2789
              | i >= n = error $ printf "AtLeastHandler.constrReasonOf: cannot find falsified literal in first %d elements" n
×
2790
              | otherwise = do
1✔
2791
                  lit <- readLitArray (atLeastLits this) i
1✔
2792
                  val <- litValue solver lit
1✔
2793
                  if val == lFalse
1✔
2794
                  then return lit
1✔
2795
                  else go (i+1)
1✔
2796
        lit <- go 0
1✔
2797
        return $ lit : falsifiedLits
1✔
2798
      Just lit -> do
1✔
2799
        when debugMode $ do
×
2800
          es <- getLits (atLeastLits this)
×
2801
          unless (lit `elem` take n es) $
×
2802
            error $ printf "AtLeastHandler.constrReasonOf: cannot find %d in first %d elements" n
×
2803
        return falsifiedLits
1✔
2804

2805
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2806

2807
  isPBRepresentable _ = return True
1✔
2808

2809
  toPBLinAtLeast this = do
1✔
2810
    lits <- getLits (atLeastLits this)
1✔
2811
    return ([(1,l) | l <- lits], fromIntegral (atLeastNum this))
1✔
2812

2813
  isSatisfied solver this = do
1✔
2814
    m <- getLitArraySize (atLeastLits this)
1✔
2815
    liftM isLeft $ runExceptT $ numLoopState 0 (m-1) 0 $ \(!n) i -> do
1✔
2816
      v <- lift $ litValue solver =<< readLitArray (atLeastLits this) i
1✔
2817
      if v /= lTrue then do
1✔
2818
        return n
1✔
2819
      else do
1✔
2820
        let n' = n + 1
1✔
2821
        when (n' >= atLeastNum this) $ throwE ()
×
2822
        return n'
1✔
2823

2824
  constrReadActivity this = readIORef (atLeastActivity this)
1✔
2825

2826
  constrWriteActivity this aval = writeIORef (atLeastActivity this) $! aval
1✔
2827

2828
basicAttachAtLeastHandler :: Solver -> AtLeastHandler -> IO Bool
2829
basicAttachAtLeastHandler solver this = do
1✔
2830
  lits <- getLits (atLeastLits this)
1✔
2831
  let m = length lits
1✔
2832
      n = atLeastNum this
1✔
2833
      constr = toConstraintHandler this
1✔
2834
  if m < n then do
×
2835
    markBad solver
×
2836
    return False
×
2837
  else if m == n then do
×
2838
    allM (\l -> assignBy solver l constr) lits
×
2839
  else do -- m > n
1✔
2840
    forM_ (take (n+1) lits) $ \l -> watchLit solver l constr
1✔
2841
    return True
×
2842

2843
{--------------------------------------------------------------------
2844
  Pseudo Boolean Constraint
2845
--------------------------------------------------------------------}
2846

2847
newPBHandler :: Solver -> PBLinSum -> Integer -> Bool -> IO SomeConstraintHandler
2848
newPBHandler solver ts degree learnt = do
1✔
2849
  config <- configPBHandlerType <$> getConfig solver
1✔
2850
  case config of
1✔
2851
    PBHandlerTypeCounter -> do
1✔
2852
      c <- newPBHandlerCounter ts degree learnt
1✔
2853
      return (toConstraintHandler c)
1✔
2854
    PBHandlerTypePueblo -> do
1✔
2855
      c <- newPBHandlerPueblo ts degree learnt
1✔
2856
      return (toConstraintHandler c)
1✔
2857

2858
newPBHandlerPromoted :: Solver -> PBLinSum -> Integer -> Bool -> IO SomeConstraintHandler
2859
newPBHandlerPromoted solver lhs rhs learnt = do
1✔
2860
  case pbToAtLeast (lhs,rhs) of
1✔
2861
    Nothing -> newPBHandler solver lhs rhs learnt
1✔
2862
    Just (lhs2, rhs2) -> do
1✔
2863
      if rhs2 /= 1 then do
×
2864
        h <- newAtLeastHandler lhs2 rhs2 learnt
1✔
2865
        return $ toConstraintHandler h
1✔
2866
      else do
×
2867
        h <- newClauseHandler lhs2 learnt
×
2868
        return $ toConstraintHandler h
×
2869

2870
pbOverSAT :: Solver -> PBLinAtLeast -> IO Bool
2871
pbOverSAT solver (lhs, rhs) = do
1✔
2872
  ss <- forM lhs $ \(c,l) -> do
1✔
2873
    v <- litValue solver l
1✔
2874
    if v /= lFalse
1✔
2875
      then return c
1✔
2876
      else return 0
1✔
2877
  return $! sum ss > rhs
1✔
2878

2879
pbToAtLeast :: PBLinAtLeast -> Maybe AtLeast
2880
pbToAtLeast (lhs, rhs) = do
1✔
2881
  let cs = [c | (c,_) <- lhs]
1✔
2882
  guard $ Set.size (Set.fromList cs) == 1
1✔
2883
  let c = head cs
1✔
2884
  return $ (map snd lhs, fromInteger ((rhs+c-1) `div` c))
1✔
2885

2886
pbToClause :: PBLinAtLeast -> Maybe Clause
2887
pbToClause pb = do
1✔
2888
  (lhs, rhs) <- pbToAtLeast pb
1✔
2889
  guard $ rhs == 1
1✔
2890
  return lhs
×
2891

2892
{--------------------------------------------------------------------
2893
  Pseudo Boolean Constraint (Counter)
2894
--------------------------------------------------------------------}
2895

2896
data PBHandlerCounter
2897
  = PBHandlerCounter
2898
  { pbTerms    :: !PBLinSum -- sorted in the decending order on coefficients.
1✔
2899
  , pbDegree   :: !Integer
1✔
2900
  , pbCoeffMap :: !(LitMap Integer)
1✔
2901
  , pbMaxSlack :: !Integer
1✔
2902
  , pbSlack    :: !(IORef Integer)
1✔
2903
  , pbActivity :: !(IORef Double)
1✔
2904
  , pbHash     :: !Int
1✔
2905
  }
2906

2907
instance Eq PBHandlerCounter where
2908
  (==) = (==) `on` pbSlack
1✔
2909

2910
instance Hashable PBHandlerCounter where
2911
  hash = pbHash
1✔
2912
  hashWithSalt = defaultHashWithSalt
1✔
2913

2914
newPBHandlerCounter :: PBLinSum -> Integer -> Bool -> IO PBHandlerCounter
2915
newPBHandlerCounter ts degree learnt = do
1✔
2916
  let ts' = sortBy (flip compare `on` fst) ts
1✔
2917
      slack = sum (map fst ts) - degree
1✔
2918
      m = IM.fromList [(l,c) | (c,l) <- ts]
1✔
2919
  s <- newIORef slack
×
2920
  act <- newIORef $! (if learnt then 0 else -1)
1✔
2921
  return (PBHandlerCounter ts' degree m slack s act (hash (ts,degree)))
1✔
2922

2923
instance ConstraintHandler PBHandlerCounter where
2924
  toConstraintHandler = CHPBCounter
1✔
2925

2926
  showConstraintHandler this = do
×
2927
    return $ show (pbTerms this) ++ " >= " ++ show (pbDegree this)
×
2928

2929
  constrAttach solver this this2 = do
1✔
2930
    -- BCP queue should be empty at this point.
2931
    -- It is important for calculating slack.
2932
    bcpCheckEmpty solver
1✔
2933
    s <- liftM sum $ forM (pbTerms this2) $ \(c,l) -> do
1✔
2934
      watchLit solver l this
1✔
2935
      val <- litValue solver l
1✔
2936
      if val == lFalse then do
×
2937
        addOnUnassigned solver this l
×
2938
        return 0
×
2939
      else do
1✔
2940
        return c
1✔
2941
    let slack = s - pbDegree this2
1✔
2942
    writeIORef (pbSlack this2) $! slack
1✔
2943
    if slack < 0 then
×
2944
      return False
×
2945
    else do
1✔
2946
      flip allM (pbTerms this2) $ \(c,l) -> do
1✔
2947
        val <- litValue solver l
1✔
2948
        if c > slack && val == lUndef then do
1✔
2949
          assignBy solver l this
×
2950
        else
2951
          return True
1✔
2952

2953
  constrDetach solver this this2 = do
1✔
2954
    forM_ (pbTerms this2) $ \(_,l) -> do
1✔
2955
      unwatchLit solver l this
1✔
2956

2957
  constrIsLocked solver this this2 = do
1✔
2958
    anyM (\(_,l) -> isReasonOf solver this l) (pbTerms this2)
×
2959

2960
  constrPropagate solver this this2 falsifiedLit = do
1✔
2961
    watchLit solver falsifiedLit this
1✔
2962
    let c = pbCoeffMap this2 IM.! falsifiedLit
1✔
2963
    modifyIORef' (pbSlack this2) (subtract c)
1✔
2964
    addOnUnassigned solver this falsifiedLit
1✔
2965
    s <- readIORef (pbSlack this2)
1✔
2966
    if s < 0 then
1✔
2967
      return False
1✔
2968
    else do
1✔
2969
      forM_ (takeWhile (\(c1,_) -> c1 > s) (pbTerms this2)) $ \(_,l1) -> do
1✔
2970
        v <- litValue solver l1
1✔
2971
        when (v == lUndef) $ do
1✔
2972
          assignBy solver l1 this
1✔
2973
          return ()
×
2974
      return True
1✔
2975

2976
  constrReasonOf solver this l = do
1✔
2977
    case l of
1✔
2978
      Nothing -> do
1✔
2979
        let p _ = return True
1✔
2980
        f p (pbMaxSlack this) (pbTerms this)
1✔
2981
      Just lit -> do
1✔
2982
        idx <- varAssignNo solver (litVar lit)
1✔
2983
        -- PB制約の場合には複数回unitになる可能性があり、
2984
        -- litへの伝播以降に割り当てられたリテラルを含まないよう注意が必要
2985
        let p lit2 =do
1✔
2986
              idx2 <- varAssignNo solver (litVar lit2)
1✔
2987
              return $ idx2 < idx
1✔
2988
        let c = pbCoeffMap this IM.! lit
1✔
2989
        f p (pbMaxSlack this - c) (pbTerms this)
1✔
2990
    where
2991
      {-# INLINE f #-}
2992
      f :: (Lit -> IO Bool) -> Integer -> PBLinSum -> IO [Lit]
2993
      f p s xs = go s xs []
1✔
2994
        where
2995
          go :: Integer -> PBLinSum -> [Lit] -> IO [Lit]
2996
          go s _ ret | s < 0 = return ret
1✔
2997
          go _ [] _ = error "PBHandlerCounter.constrReasonOf: should not happen"
×
2998
          go s ((c,lit):xs) ret = do
1✔
2999
            val <- litValue solver lit
1✔
3000
            if val == lFalse then do
1✔
3001
              b <- p lit
1✔
3002
              if b
×
3003
              then go (s - c) xs (lit:ret)
1✔
3004
              else go s xs ret
×
3005
            else do
1✔
3006
              go s xs ret
1✔
3007

3008
  constrOnUnassigned _solver _this this2 lit = do
1✔
3009
    let c = pbCoeffMap this2 IM.! (- lit)
1✔
3010
    modifyIORef' (pbSlack this2) (+ c)
1✔
3011

3012
  isPBRepresentable _ = return True
1✔
3013

3014
  toPBLinAtLeast this = do
1✔
3015
    return (pbTerms this, pbDegree this)
1✔
3016

3017
  isSatisfied solver this = do
1✔
3018
    xs <- forM (pbTerms this) $ \(c,l) -> do
1✔
3019
      v <- litValue solver l
1✔
3020
      if v == lTrue
1✔
3021
        then return c
1✔
3022
        else return 0
1✔
3023
    return $ sum xs >= pbDegree this
1✔
3024

3025
  constrWeight _ _ = return 0.5
×
3026

3027
  constrReadActivity this = readIORef (pbActivity this)
1✔
3028

3029
  constrWriteActivity this aval = writeIORef (pbActivity this) $! aval
1✔
3030

3031
{--------------------------------------------------------------------
3032
  Pseudo Boolean Constraint (Pueblo)
3033
--------------------------------------------------------------------}
3034

3035
data PBHandlerPueblo
3036
  = PBHandlerPueblo
3037
  { puebloTerms     :: !PBLinSum
1✔
3038
  , puebloDegree    :: !Integer
1✔
3039
  , puebloMaxSlack  :: !Integer
1✔
3040
  , puebloWatches   :: !(IORef LitSet)
1✔
3041
  , puebloWatchSum  :: !(IORef Integer)
1✔
3042
  , puebloActivity  :: !(IORef Double)
1✔
3043
  , puebloHash      :: !Int
1✔
3044
  }
3045

3046
instance Eq PBHandlerPueblo where
3047
  (==) = (==) `on` puebloWatchSum
1✔
3048

3049
instance Hashable PBHandlerPueblo where
3050
  hash = puebloHash
1✔
3051
  hashWithSalt = defaultHashWithSalt
1✔
3052

3053
puebloAMax :: PBHandlerPueblo -> Integer
3054
puebloAMax this =
1✔
3055
  case puebloTerms this of
1✔
3056
    (c,_):_ -> c
1✔
3057
    [] -> 0 -- should not happen?
×
3058

3059
newPBHandlerPueblo :: PBLinSum -> Integer -> Bool -> IO PBHandlerPueblo
3060
newPBHandlerPueblo ts degree learnt = do
1✔
3061
  let ts' = sortBy (flip compare `on` fst) ts
1✔
3062
      slack = sum [c | (c,_) <- ts'] - degree
1✔
3063
  ws   <- newIORef IS.empty
1✔
3064
  wsum <- newIORef 0
1✔
3065
  act  <- newIORef $! (if learnt then 0 else -1)
×
3066
  return $ PBHandlerPueblo ts' degree slack ws wsum act (hash (ts,degree))
1✔
3067

3068
puebloGetWatchSum :: PBHandlerPueblo -> IO Integer
3069
puebloGetWatchSum pb = readIORef (puebloWatchSum pb)
1✔
3070

3071
puebloWatch :: Solver -> SomeConstraintHandler -> PBHandlerPueblo -> PBLinTerm -> IO ()
3072
puebloWatch solver constr !pb (c, lit) = do
1✔
3073
  watchLit solver lit constr
1✔
3074
  modifyIORef' (puebloWatches pb) (IS.insert lit)
1✔
3075
  modifyIORef' (puebloWatchSum pb) (+c)
1✔
3076

3077
puebloUnwatch :: Solver -> PBHandlerPueblo -> PBLinTerm -> IO ()
3078
puebloUnwatch _solver pb (c, lit) = do
1✔
3079
  modifyIORef' (puebloWatches pb) (IS.delete lit)
1✔
3080
  modifyIORef' (puebloWatchSum pb) (subtract c)
1✔
3081

3082
instance ConstraintHandler PBHandlerPueblo where
3083
  toConstraintHandler = CHPBPueblo
1✔
3084

3085
  showConstraintHandler this = do
×
3086
    return $ show (puebloTerms this) ++ " >= " ++ show (puebloDegree this)
×
3087

3088
  constrAttach solver this this2 = do
1✔
3089
    bcpCheckEmpty solver
1✔
3090
    ret <- puebloPropagate solver this this2
1✔
3091

3092
    -- register to watch recently falsified literals to recover
3093
    -- "WatchSum >= puebloDegree this + puebloAMax this" when backtrack is performed.
3094
    wsum <- puebloGetWatchSum this2
1✔
3095
    unless (wsum >= puebloDegree this2 + puebloAMax this2) $ do
1✔
3096
      let f m tm@(_,lit) = do
1✔
3097
            val <- litValue solver lit
1✔
3098
            if val == lFalse then do
×
3099
              idx <- varAssignNo solver (litVar lit)
×
3100
              return (IM.insert idx tm m)
×
3101
            else
3102
              return m
1✔
3103
      xs <- liftM (map snd . IM.toDescList) $ foldM f IM.empty (puebloTerms this2)
×
3104
      let g !_ [] = return ()
×
3105
          g !s ((c,l):ts) = do
×
3106
            addOnUnassigned solver this l
×
3107
            if s+c >= puebloDegree this2 + puebloAMax this2 then return ()
×
3108
            else g (s+c) ts
×
3109
      g wsum xs
1✔
3110

3111
    return ret
1✔
3112

3113
  constrDetach solver this this2 = do
1✔
3114
    ws <- readIORef (puebloWatches this2)
1✔
3115
    forM_ (IS.toList ws) $ \l -> do
1✔
3116
      unwatchLit solver l this
×
3117

3118
  constrIsLocked solver this this2 = do
1✔
3119
    anyM (\(_,l) -> isReasonOf solver this l) (puebloTerms this2)
×
3120

3121
  constrPropagate solver this this2 falsifiedLit = do
1✔
3122
    let t = fromJust $ find (\(_,l) -> l==falsifiedLit) (puebloTerms this2)
1✔
3123
    puebloUnwatch solver this2 t
×
3124
    ret <- puebloPropagate solver this this2
1✔
3125
    wsum <- puebloGetWatchSum this2
1✔
3126
    unless (wsum >= puebloDegree this2 + puebloAMax this2) $
1✔
3127
      addOnUnassigned solver this falsifiedLit
1✔
3128
    return ret
1✔
3129

3130
  constrReasonOf solver this l = do
1✔
3131
    case l of
1✔
3132
      Nothing -> do
1✔
3133
        let p _ = return True
1✔
3134
        f p (puebloMaxSlack this) (puebloTerms this)
1✔
3135
      Just lit -> do
1✔
3136
        idx <- varAssignNo solver (litVar lit)
1✔
3137
        -- PB制約の場合には複数回unitになる可能性があり、
3138
        -- litへの伝播以降に割り当てられたリテラルを含まないよう注意が必要
3139
        let p lit2 =do
1✔
3140
              idx2 <- varAssignNo solver (litVar lit2)
1✔
3141
              return $ idx2 < idx
1✔
3142
        let c = fst $ fromJust $ find (\(_,l) -> l == lit) (puebloTerms this)
1✔
3143
        f p (puebloMaxSlack this - c) (puebloTerms this)
1✔
3144
    where
3145
      {-# INLINE f #-}
3146
      f :: (Lit -> IO Bool) -> Integer -> PBLinSum -> IO [Lit]
3147
      f p s xs = go s xs []
1✔
3148
        where
3149
          go :: Integer -> PBLinSum -> [Lit] -> IO [Lit]
3150
          go s _ ret | s < 0 = return ret
1✔
3151
          go _ [] _ = error "PBHandlerPueblo.constrReasonOf: should not happen"
×
3152
          go s ((c,lit):xs) ret = do
1✔
3153
            val <- litValue solver lit
1✔
3154
            if val == lFalse then do
1✔
3155
              b <- p lit
1✔
3156
              if b
1✔
3157
              then go (s - c) xs (lit:ret)
1✔
3158
              else go s xs ret
1✔
3159
            else do
1✔
3160
              go s xs ret
1✔
3161

3162
  constrOnUnassigned solver this this2 lit = do
1✔
3163
    let t = fromJust $ find (\(_,l) -> l == - lit) (puebloTerms this2)
1✔
3164
    puebloWatch solver this this2 t
1✔
3165

3166
  isPBRepresentable _ = return True
1✔
3167

3168
  toPBLinAtLeast this = do
1✔
3169
    return (puebloTerms this, puebloDegree this)
1✔
3170

3171
  isSatisfied solver this = do
1✔
3172
    xs <- forM (puebloTerms this) $ \(c,l) -> do
1✔
3173
      v <- litValue solver l
1✔
3174
      if v == lTrue
1✔
3175
        then return c
1✔
3176
        else return 0
1✔
3177
    return $ sum xs >= puebloDegree this
1✔
3178

3179
  constrWeight _ _ = return 0.5
×
3180

3181
  constrReadActivity this = readIORef (puebloActivity this)
1✔
3182

3183
  constrWriteActivity this aval = writeIORef (puebloActivity this) $! aval
×
3184

3185
puebloPropagate :: Solver -> SomeConstraintHandler -> PBHandlerPueblo -> IO Bool
3186
puebloPropagate solver constr this = do
1✔
3187
  puebloUpdateWatchSum solver constr this
1✔
3188
  watchsum <- puebloGetWatchSum this
1✔
3189
  if puebloDegree this + puebloAMax this <= watchsum then
1✔
3190
    return True
1✔
3191
  else if watchsum < puebloDegree this then do
1✔
3192
    -- CONFLICT
3193
    return False
1✔
3194
  else do -- puebloDegree this <= watchsum < puebloDegree this + puebloAMax this
1✔
3195
    -- UNIT PROPAGATION
3196
    let f [] = return True
1✔
3197
        f ((c,lit) : ts) = do
1✔
3198
          watchsum' <- puebloGetWatchSum this
1✔
3199
          if watchsum' - c >= puebloDegree this then
1✔
3200
            return True
1✔
3201
          else do
1✔
3202
            val <- litValue solver lit
1✔
3203
            when (val == lUndef) $ do
1✔
3204
              b <- assignBy solver lit constr
1✔
3205
              assert b $ return ()
×
3206
            f ts
1✔
3207
    f $ puebloTerms this
1✔
3208

3209
puebloUpdateWatchSum :: Solver -> SomeConstraintHandler -> PBHandlerPueblo -> IO ()
3210
puebloUpdateWatchSum solver constr this = do
1✔
3211
  let f [] = return ()
×
3212
      f (t@(_,lit):ts) = do
1✔
3213
        watchSum <- puebloGetWatchSum this
1✔
3214
        if watchSum >= puebloDegree this + puebloAMax this then
1✔
3215
          return ()
×
3216
        else do
1✔
3217
          val <- litValue solver lit
1✔
3218
          watched <- liftM (lit `IS.member`) $ readIORef (puebloWatches this)
1✔
3219
          when (val /= lFalse && not watched) $ do
1✔
3220
            puebloWatch solver constr this t
1✔
3221
          f ts
1✔
3222
  f (puebloTerms this)
1✔
3223

3224
{--------------------------------------------------------------------
3225
  XOR Clause
3226
--------------------------------------------------------------------}
3227

3228
data XORClauseHandler
3229
  = XORClauseHandler
3230
  { xorLits :: !LitArray
1✔
3231
  , xorActivity :: !(IORef Double)
1✔
3232
  , xorHash :: !Int
×
3233
  }
3234

3235
instance Eq XORClauseHandler where
3236
  (==) = (==) `on` xorLits
1✔
3237

3238
instance Hashable XORClauseHandler where
3239
  hash = xorHash
×
3240
  hashWithSalt = defaultHashWithSalt
×
3241

3242
newXORClauseHandler :: [Lit] -> Bool -> IO XORClauseHandler
3243
newXORClauseHandler ls learnt = do
1✔
3244
  a <- newLitArray ls
1✔
3245
  act <- newIORef $! (if learnt then 0 else -1)
×
3246
  return (XORClauseHandler a act (hash ls))
1✔
3247

3248
instance ConstraintHandler XORClauseHandler where
3249
  toConstraintHandler = CHXORClause
1✔
3250

3251
  showConstraintHandler this = do
×
3252
    lits <- getLits (xorLits this)
×
3253
    return ("XOR " ++ show lits)
×
3254

3255
  constrAttach solver this this2 = do
×
3256
    -- BCP Queue should be empty at this point.
3257
    -- If not, duplicated propagation happens.
3258
    bcpCheckEmpty solver
×
3259

3260
    let a = xorLits this2
×
3261
    size <- getLitArraySize a
×
3262

3263
    if size == 0 then do
×
3264
      markBad solver
×
3265
      return False
×
3266
    else if size == 1 then do
×
3267
      lit0 <- readLitArray a 0
×
3268
      assignBy solver lit0 this
×
3269
    else do
×
3270
      ref <- newIORef 1
×
3271
      let f i = do
×
3272
            lit_i <- readLitArray a i
×
3273
            val_i <- litValue solver lit_i
×
3274
            if val_i == lUndef then
×
3275
              return True
×
3276
            else do
×
3277
              j <- readIORef ref
×
3278
              k <- findForWatch2 solver a j (size - 1)
×
3279
              case k of
×
3280
                -1 -> do
×
3281
                  return False
×
3282
                _ -> do
×
3283
                  lit_k <- readLitArray a k
×
3284
                  writeLitArray a i lit_k
×
3285
                  writeLitArray a k lit_i
×
3286
                  writeIORef ref $! (k+1)
×
3287
                  return True
×
3288

3289
      b <- f 0
×
3290
      if b then do
×
3291
        lit0 <- readLitArray a 0
×
3292
        watchVar solver (litVar lit0) this
×
3293
        b2 <- f 1
×
3294
        if b2 then do
×
3295
          lit1 <- readLitArray a 1
×
3296
          watchVar solver (litVar lit1) this
×
3297
          return True
×
3298
        else do -- UNIT
×
3299
          -- We need to watch the most recently falsified literal
3300
          (i,_) <- liftM (maximumBy (comparing snd)) $ forM [1..size-1] $ \l -> do
×
3301
            lit <- readLitArray a l
×
3302
            lv <- litLevel solver lit
×
3303
            return (l,lv)
×
3304
          lit1 <- readLitArray a 1
×
3305
          liti <- readLitArray a i
×
3306
          writeLitArray a 1 liti
×
3307
          writeLitArray a i lit1
×
3308
          watchVar solver (litVar liti) this
×
3309
          -- lit0 ⊕ y
3310
          y <- do
×
3311
            ref' <- newIORef False
×
3312
            forLoop 1 (<size) (+1) $ \j -> do
×
3313
              lit_j <- readLitArray a j
×
3314
              val_j <- litValue solver lit_j
×
3315
              modifyIORef' ref' (/= fromJust (unliftBool val_j))
×
3316
            readIORef ref'
×
3317
          assignBy solver (if y then litNot lit0 else lit0) this -- should always succeed
×
3318
      else do
×
3319
        ls <- liftM (map fst . sortBy (flip (comparing snd))) $ forM [0..size-1] $ \l -> do
×
3320
          lit <- readLitArray a l
×
3321
          lv <- litLevel solver lit
×
3322
          return (l,lv)
×
3323
        forM_ (zip [0..] ls) $ \(i,lit) -> do
×
3324
          writeLitArray a i lit
×
3325
        lit0 <- readLitArray a 0
×
3326
        lit1 <- readLitArray a 1
×
3327
        watchVar solver (litVar lit0) this
×
3328
        watchVar solver (litVar lit1) this
×
3329
        isSatisfied solver this2
×
3330

3331
  constrDetach solver this this2 = do
1✔
3332
    size <- getLitArraySize (xorLits this2)
1✔
3333
    when (size >= 2) $ do
1✔
3334
      lit0 <- readLitArray (xorLits this2) 0
1✔
3335
      lit1 <- readLitArray (xorLits this2) 1
1✔
3336
      unwatchVar solver (litVar lit0) this
×
3337
      unwatchVar solver (litVar lit1) this
×
3338

3339
  constrIsLocked solver this this2 = do
1✔
3340
    lit0 <- readLitArray (xorLits this2) 0
1✔
3341
    lit1 <- readLitArray (xorLits this2) 1
1✔
3342
    b0 <- isReasonOf solver this lit0
1✔
3343
    b1 <- isReasonOf solver this lit1
1✔
3344
    return $ b0 || b1
1✔
3345

3346
  constrPropagate !solver this this2 !falsifiedLit = do
1✔
3347
    b <- constrIsLocked solver this this2
1✔
3348
    if b then
1✔
3349
      return True
1✔
3350
    else do
1✔
3351
      preprocess
1✔
3352

3353
      !lit0 <- readLitArray a 0
1✔
3354
      !size <- getLitArraySize (xorLits this2)
1✔
3355
      i <- findForWatch2 solver a 2 (size - 1)
1✔
3356
      case i of
1✔
3357
        -1 -> do
1✔
3358
          when debugMode $ logIO solver $ do
×
3359
             str <- showConstraintHandler this
×
3360
             return $ printf "constrPropagate: %s is unit" str
×
3361
          watchVar solver v this
1✔
3362
          -- lit0 ⊕ y
3363
          y <- do
1✔
3364
            ref <- newIORef False
1✔
3365
            forLoop 1 (<size) (+1) $ \j -> do
1✔
3366
              lit_j <- readLitArray a j
1✔
3367
              val_j <- litValue solver lit_j
1✔
3368
              modifyIORef' ref (/= fromJust (unliftBool val_j))
1✔
3369
            readIORef ref
1✔
3370
          assignBy solver (if y then litNot lit0 else lit0) this
1✔
3371
        _  -> do
1✔
3372
          !lit1 <- readLitArray a 1
1✔
3373
          !liti <- readLitArray a i
1✔
3374
          writeLitArray a 1 liti
1✔
3375
          writeLitArray a i lit1
1✔
3376
          watchVar solver (litVar liti) this
1✔
3377
          return True
1✔
3378

3379
    where
3380
      v = litVar falsifiedLit
1✔
3381
      a = xorLits this2
1✔
3382

3383
      preprocess :: IO ()
3384
      preprocess = do
1✔
3385
        !l0 <- readLitArray a 0
1✔
3386
        !l1 <- readLitArray a 1
1✔
3387
        assert (litVar l0 == v || litVar l1 == v) $ return ()
×
3388
        when (litVar l0 == v) $ do
1✔
3389
          writeLitArray a 0 l1
1✔
3390
          writeLitArray a 1 l0
1✔
3391

3392
  constrReasonOf solver this l = do
1✔
3393
    lits <- getLits (xorLits this)
1✔
3394
    xs <-
3395
      case l of
1✔
3396
        Nothing -> mapM f lits
1✔
3397
        Just lit -> do
1✔
3398
         case lits of
1✔
3399
           l1:ls -> do
1✔
3400
             assert (litVar lit == litVar l1) $ return ()
×
3401
             mapM f ls
1✔
3402
           _ -> error "XORClauseHandler.constrReasonOf: should not happen"
×
3403
    return xs
1✔
3404
    where
3405
      f :: Lit -> IO Lit
3406
      f lit = do
1✔
3407
        let v = litVar lit
1✔
3408
        val <- varValue solver v
1✔
3409
        return $ literal v (not (fromJust (unliftBool val)))
1✔
3410

3411
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3412

3413
  isPBRepresentable _ = return False
1✔
3414

3415
  toPBLinAtLeast _ = error "XORClauseHandler does not support toPBLinAtLeast"
×
3416

3417
  isSatisfied solver this = do
1✔
3418
    lits <- getLits (xorLits this)
1✔
3419
    vals <- mapM (litValue solver) lits
1✔
3420
    let f x y
1✔
3421
          | x == lUndef || y == lUndef = lUndef
1✔
3422
          | otherwise = liftBool (x /= y)
1✔
3423
    return $ foldl' f lFalse vals == lTrue
1✔
3424

3425
  constrIsProtected _ this = do
×
3426
    size <- getLitArraySize (xorLits this)
×
3427
    return $! size <= 2
×
3428

3429
  constrReadActivity this = readIORef (xorActivity this)
1✔
3430

3431
  constrWriteActivity this aval = writeIORef (xorActivity this) $! aval
×
3432

3433
basicAttachXORClauseHandler :: Solver -> XORClauseHandler -> IO Bool
3434
basicAttachXORClauseHandler solver this = do
1✔
3435
  lits <- getLits (xorLits this)
1✔
3436
  let constr = toConstraintHandler this
1✔
3437
  case lits of
1✔
3438
    [] -> do
×
3439
      markBad solver
×
3440
      return False
×
3441
    [l1] -> do
×
3442
      assignBy solver l1 constr
×
3443
    l1:l2:_ -> do
1✔
3444
      watchVar solver (litVar l1) constr
1✔
3445
      watchVar solver (litVar l2) constr
1✔
3446
      return True
×
3447

3448
{--------------------------------------------------------------------
3449
  Arbitrary Boolean Theory
3450
--------------------------------------------------------------------}
3451

3452
setTheory :: Solver -> TheorySolver -> IO ()
3453
setTheory solver tsolver = do
1✔
3454
  d <- getDecisionLevel solver
1✔
3455
  assert (d == levelRoot) $ return ()
×
3456

3457
  m <- readIORef (svTheorySolver solver)
1✔
3458
  case m of
1✔
3459
    Just _ -> do
×
3460
      error $ "ToySolver.SAT.setTheory: cannot replace TheorySolver"
×
3461
    Nothing -> do
1✔
3462
      writeIORef (svTheorySolver solver) (Just tsolver)
1✔
3463
      ret <- deduce solver
1✔
3464
      case ret of
1✔
3465
        Nothing -> return ()
×
3466
        Just _ -> markBad solver
1✔
3467

3468
getTheory :: Solver -> IO (Maybe TheorySolver)
3469
getTheory solver = readIORef (svTheorySolver solver)
1✔
3470

3471
deduceT :: Solver -> ExceptT SomeConstraintHandler IO ()
3472
deduceT solver = do
1✔
3473
  mt <- liftIO $ readIORef (svTheorySolver solver)
1✔
3474
  case mt of
1✔
3475
    Nothing -> return ()
×
3476
    Just t -> do
1✔
3477
      n <- liftIO $ Vec.getSize (svTrail solver)
1✔
3478
      let h = CHTheory TheoryHandler
1✔
3479
          callback l = assignBy solver l h
1✔
3480
          loop i = do
1✔
3481
            when (i < n) $ do
1✔
3482
              l <- liftIO $ Vec.unsafeRead (svTrail solver) i
1✔
3483
              ok <- liftIO $ thAssertLit t callback l
×
3484
              if ok then
×
3485
                loop (i+1)
1✔
3486
              else
3487
                throwE h
×
3488
      loop =<< liftIO (readIOURef (svTheoryChecked solver))
1✔
3489
      b2 <- liftIO $ thCheck t callback
1✔
3490
      if b2 then do
1✔
3491
        liftIO $ writeIOURef (svTheoryChecked solver) n
1✔
3492
      else
3493
        throwE h
1✔
3494

3495
data TheoryHandler = TheoryHandler deriving (Eq)
×
3496

3497
instance Hashable TheoryHandler where
3498
  hash _ = hash ()
×
3499
  hashWithSalt = defaultHashWithSalt
×
3500

3501
instance ConstraintHandler TheoryHandler where
3502
  toConstraintHandler = CHTheory
×
3503

3504
  showConstraintHandler _this = return "TheoryHandler"
×
3505

3506
  constrAttach _solver _this _this2 = error "TheoryHandler.constrAttach"
×
3507

3508
  constrDetach _solver _this _this2 = return ()
×
3509

3510
  constrIsLocked _solver _this _this2 = return True
×
3511

3512
  constrPropagate _solver _this _this2 _falsifiedLit =  error "TheoryHandler.constrPropagate"
×
3513

3514
  constrReasonOf solver _this l = do
1✔
3515
    Just t <- readIORef (svTheorySolver solver)
1✔
3516
    lits <- thExplain t l
1✔
3517
    return $ [-lit | lit <- lits]
1✔
3518

3519
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3520

3521
  isPBRepresentable _this = return False
1✔
3522

3523
  toPBLinAtLeast _this = error "TheoryHandler.toPBLinAtLeast"
×
3524

3525
  isSatisfied _solver _this = error "TheoryHandler.isSatisfied"
×
3526

3527
  constrIsProtected _solver _this = error "TheoryHandler.constrIsProtected"
×
3528

3529
  constrReadActivity _this = return 0
1✔
3530

3531
  constrWriteActivity _this _aval = return ()
×
3532

3533
{--------------------------------------------------------------------
3534
  Restart strategy
3535
--------------------------------------------------------------------}
3536

3537
mkRestartSeq :: RestartStrategy -> Int -> Double -> [Int]
3538
mkRestartSeq MiniSATRestarts = miniSatRestartSeq
1✔
3539
mkRestartSeq ArminRestarts   = arminRestartSeq
1✔
3540
mkRestartSeq LubyRestarts    = lubyRestartSeq
1✔
3541

3542
miniSatRestartSeq :: Int -> Double -> [Int]
3543
miniSatRestartSeq start inc = iterate (ceiling . (inc *) . fromIntegral) start
1✔
3544

3545
{-
3546
miniSatRestartSeq :: Int -> Double -> [Int]
3547
miniSatRestartSeq start inc = map round $ iterate (inc*) (fromIntegral start)
3548
-}
3549

3550
arminRestartSeq :: Int -> Double -> [Int]
3551
arminRestartSeq start inc = go (fromIntegral start) (fromIntegral start)
1✔
3552
  where
3553
    go !inner !outer = round inner : go inner' outer'
1✔
3554
      where
3555
        (inner',outer') =
3556
          if inner >= outer
×
3557
          then (fromIntegral start, outer * inc)
1✔
3558
          else (inner * inc, outer)
×
3559

3560
lubyRestartSeq :: Int -> Double -> [Int]
3561
lubyRestartSeq start inc = map (ceiling . (fromIntegral start *) . luby inc) [0..]
×
3562

3563
{-
3564
  Finite subsequences of the Luby-sequence:
3565

3566
  0: 1
3567
  1: 1 1 2
3568
  2: 1 1 2 1 1 2 4
3569
  3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
3570
  ...
3571

3572

3573
-}
3574
luby :: Double -> Integer -> Double
3575
luby y x = go2 size1 sequ1 x
1✔
3576
  where
3577
    -- Find the finite subsequence that contains index 'x', and the
3578
    -- size of that subsequence:
3579
    (size1, sequ1) = go 1 0
1✔
3580

3581
    go :: Integer -> Integer -> (Integer, Integer)
3582
    go size sequ
1✔
3583
      | size < x+1 = go (2*size+1) (sequ+1)
×
3584
      | otherwise  = (size, sequ)
1✔
3585

3586
    go2 :: Integer -> Integer -> Integer -> Double
3587
    go2 size sequ x2
1✔
3588
      | size-1 /= x2 = let size' = (size-1) `div` 2 in go2 size' (sequ - 1) (x2 `mod` size')
×
3589
      | otherwise = y ^ sequ
×
3590

3591

3592
{--------------------------------------------------------------------
3593
  utility
3594
--------------------------------------------------------------------}
3595

3596
allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
3597
allM p = go
1✔
3598
  where
3599
    go [] = return True
1✔
3600
    go (x:xs) = do
1✔
3601
      b <- p x
1✔
3602
      if b
1✔
3603
        then go xs
1✔
3604
        else return False
1✔
3605

3606
anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool
3607
anyM p = go
1✔
3608
  where
3609
    go [] = return False
1✔
3610
    go (x:xs) = do
1✔
3611
      b <- p x
1✔
3612
      if b
×
3613
        then return True
×
3614
        else go xs
1✔
3615

3616
shift :: IORef [a] -> IO a
3617
shift ref = do
1✔
3618
  (x:xs) <- readIORef ref
1✔
3619
  writeIORef ref xs
1✔
3620
  return x
1✔
3621

3622
defaultHashWithSalt :: Hashable a => Int -> a -> Int
3623
defaultHashWithSalt salt x = salt `combine` hash x
1✔
3624
  where
3625
    combine :: Int -> Int -> Int
3626
    combine h1 h2 = (h1 * 16777619) `xor` h2
1✔
3627

3628
{--------------------------------------------------------------------
3629
  debug
3630
--------------------------------------------------------------------}
3631

3632
debugMode :: Bool
3633
debugMode = False
1✔
3634

3635
checkSatisfied :: Solver -> IO ()
3636
checkSatisfied solver = do
1✔
3637
  cls <- readIORef (svConstrDB solver)
1✔
3638
  forM_ cls $ \c -> do
1✔
3639
    b <- isSatisfied solver c
1✔
3640
    unless b $ do
×
3641
      s <- showConstraintHandler c
×
3642
      log solver $ "BUG: " ++ s ++ " is violated"
×
3643

3644
dumpVarActivity :: Solver -> IO ()
3645
dumpVarActivity solver = do
×
3646
  log solver "Variable activity:"
×
3647
  vs <- variables solver
×
3648
  forM_ vs $ \v -> do
×
3649
    activity <- varActivity solver v
×
3650
    log solver $ printf "activity(%d) = %d" v activity
×
3651

3652
dumpConstrActivity :: Solver -> IO ()
3653
dumpConstrActivity solver = do
×
3654
  log solver "Learnt constraints activity:"
×
3655
  xs <- learntConstraints solver
×
3656
  forM_ xs $ \c -> do
×
3657
    s <- showConstraintHandler c
×
3658
    aval <- constrReadActivity c
×
3659
    log solver $ printf "activity(%s) = %f" s aval
×
3660

3661
-- | set callback function for receiving messages.
3662
setLogger :: Solver -> (String -> IO ()) -> IO ()
3663
setLogger solver logger = do
×
3664
  writeIORef (svLogger solver) (Just logger)
×
3665

3666
-- | Clear logger function set by 'setLogger'.
3667
clearLogger :: Solver -> IO ()
3668
clearLogger solver = do
×
3669
  writeIORef (svLogger solver) Nothing
×
3670

3671
log :: Solver -> String -> IO ()
3672
log solver msg = logIO solver (return msg)
×
3673

3674
logIO :: Solver -> IO String -> IO ()
3675
logIO solver action = do
1✔
3676
  m <- readIORef (svLogger solver)
1✔
3677
  case m of
1✔
3678
    Nothing -> return ()
×
3679
    Just logger -> action >>= logger
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc