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

msakai / toysolver / 513

24 Nov 2024 08:49AM UTC coverage: 68.675% (-1.0%) from 69.681%
513

push

github

web-flow
Merge 496ed4263 into 46e1509c4

5 of 121 new or added lines in 7 files covered. (4.13%)

105 existing lines in 14 files now uncovered.

9745 of 14190 relevant lines covered (68.68%)

0.69 hits per line

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

72.76
/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
#if !MIN_VERSION_hashable(1,4,3)
143
import Data.Bits (xor) -- for defining 'combine' function
144
#endif
145
import Data.Coerce
146
import Data.Default.Class
147
import Data.Either
148
import Data.Function (on)
149
import Data.Hashable
150
import Data.HashSet (HashSet)
151
import qualified Data.HashSet as HashSet
152
import Data.IORef
153
import Data.Int
154
import Data.List
155
import Data.Maybe
156
import Data.Ord
157
import qualified Data.IntMap.Strict as IM
158
import qualified Data.IntSet as IS
159
import qualified Data.Set as Set
160
import ToySolver.Internal.Data.IOURef
161
import qualified ToySolver.Internal.Data.IndexedPriorityQueue as PQ
162
import qualified ToySolver.Internal.Data.Vec as Vec
163
import Data.Typeable
164
import System.Clock
165
import qualified System.Random.MWC as Rand
166
import Text.Printf
167

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

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

179
{--------------------------------------------------------------------
180
  LitArray
181
--------------------------------------------------------------------}
182

183
newtype LitArray = LitArray (IOUArray Int PackedLit) deriving (Eq)
×
184

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

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

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

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

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

213
{--------------------------------------------------------------------
214
  internal data structures
215
--------------------------------------------------------------------}
216

217
type Level = Int
218

219
levelRoot :: Level
220
levelRoot = 0
1✔
221

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

326
  , svConstrDB     :: !(IORef [SomeConstraintHandler])
1✔
327
  , svLearntDB     :: !(IORef (Int,[SomeConstraintHandler]))
1✔
328

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

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

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

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

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

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

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

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

373
  -- ERWA / LRB
374

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

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

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

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

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

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

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

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

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

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

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

445
    Vec.push (svTrail solver) lit
1✔
446

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

453
    return True
1✔
454

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

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

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

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

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

492
  PQ.enqueue (svVarQueue solver) v
1✔
493

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

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

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

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

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

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

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

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

535
reduceDB :: Solver -> IO ()
536
reduceDB solver = do
×
537
  (_,cs) <- readIORef (svLearntDB solver)
×
538

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

545
  -- Note that False <= True
546
  let ys = sortBy (comparing snd) xs
×
547
      (zs,ws) = splitAt (length ys `div` 2) ys
×
548

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

561
  let cs2 = zs2 ++ map fst ws
×
562
      n2 = length cs2
×
563

564
  -- log solver $ printf "learnt constraints deletion: %d -> %d" n n2
565
  writeIORef (svLearntDB solver) (n2,cs2)
×
566

567
type VarActivity = Double
568

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

656
{--------------------------------------------------------------------
657
  Solver
658
--------------------------------------------------------------------}
659

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

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

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

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

701
  constrInc   <- newIOURef 1
1✔
702
  varInc   <- newIOURef 1
1✔
703

704
  configRef <- newIORef config
1✔
705

706
  learntLim       <- newIORef undefined
×
707
  learntLimAdjCnt <- newIORef (-1)
1✔
708
  learntLimSeq    <- newIORef undefined
×
709

710
  logger <- newIORef Nothing
1✔
711
  startWC    <- newIORef undefined
×
712
  lastStatWC <- newIORef undefined
×
713

714
  randgen  <- newIORef =<< Rand.create
1✔
715

716
  failed <- newIORef IS.empty
×
717
  implied <- newIORef IS.empty
×
718

719
  confBudget <- newIOURef (-1)
1✔
720
  terminateCallback <- newIORef Nothing
1✔
721
  learntCallback <- newIORef Nothing
1✔
722

723
  tsolver <- newIORef Nothing
1✔
724
  tchecked <- newIOURef 0
1✔
725

726
  seen <- Vec.new
1✔
727
  pbLearnt <- newIORef Nothing
×
728

729
  alpha <- newIOURef 0.4
1✔
730
  emaScale <- newIOURef 1.0
1✔
731
  learntCounter <- newIOURef 0
1✔
732

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

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

756
        , svConstrDB   = db
1✔
757
        , svLearntDB   = db2
1✔
758

759
        -- Theory
760
        , svTheorySolver  = tsolver
1✔
761
        , svTheoryChecked = tchecked
1✔
762

763
        -- Result
764
        , svModel      = m
1✔
765
        , svFailedAssumptions = failed
1✔
766
        , svAssumptionsImplications = implied
1✔
767

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

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

783
        -- Logging
784
        , svLogger = logger
1✔
785
        , svStartWC    = startWC
1✔
786
        , svLastStatWC = lastStatWC
1✔
787

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

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

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

818
{--------------------------------------------------------------------
819
  Problem specification
820
--------------------------------------------------------------------}
821

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1040
{--------------------------------------------------------------------
1041
  Problem solving
1042
--------------------------------------------------------------------}
1043

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

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

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

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

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

1082
    nv <- getNVars solver
1✔
1083
    Vec.resizeCapacity (svTrail solver) nv
1✔
1084

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

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

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

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

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

1132
    printStatHeader solver
1✔
1133

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

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

1154
    backtrackTo solver levelRoot
1✔
1155

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

1168
    case result of
1✔
1169
      Right x  -> return x
1✔
1170
      Left m -> m
1✔
1171

1172
data BudgetExceeded = BudgetExceeded
1173
  deriving (Show, Typeable)
×
1174

1175
instance Exception BudgetExceeded
×
1176

1177
data Canceled = Canceled
1178
  deriving (Show, Typeable)
×
1179

1180
instance Exception Canceled
×
1181

1182
data SearchResult
1183
  = SRFinished Bool
1184
  | SRRestart
1185
  | SRBudgetExceeded
1186
  | SRCanceled
1187

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

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

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

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

1257
      modifyIOURef (svNConflict solver) (+1)
1✔
1258
      d <- getDecisionLevel solver
1✔
1259

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

1264
      modifyIORef' conflictCounter (+1)
1✔
1265
      c <- readIORef conflictCounter
1✔
1266

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

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

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

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

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

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

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

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

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

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

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

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

1391
{--------------------------------------------------------------------
1392
  Simplification
1393
--------------------------------------------------------------------}
1394

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

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

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

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

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

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

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

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

1492
{--------------------------------------------------------------------
1493
  Parameter settings.
1494
--------------------------------------------------------------------}
1495

1496
{--------------------------------------------------------------------
1497
  Configulation
1498
--------------------------------------------------------------------}
1499

1500
getConfig :: Solver -> IO Config
1501
getConfig solver = readIORef $ svConfig solver
1✔
1502

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

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

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

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

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

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

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

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

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

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

1558
{--------------------------------------------------------------------
1559
  API for implementation of @solve@
1560
--------------------------------------------------------------------}
1561

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

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

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

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

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

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

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

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

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

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

1681
  pbConstrRef <- newIORef undefined
×
1682

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

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

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

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

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

1767
  lits2 <- minimizeConflictClause solver lits
1✔
1768

1769
  incrementReasoned solver (IS.toList lits2)
1✔
1770

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2098
    si :: Integer
2099
    si = fromIntegral (sec t)
×
2100

2101
    m :: Rational
2102
    m = s / 60
×
2103

2104
    mi :: Integer
2105
    mi = round m
×
2106

2107
    h :: Rational
2108
    h = m / 60
×
2109

2110
    hi :: Integer
2111
    hi = round h
×
2112

2113
{--------------------------------------------------------------------
2114
  constraint implementation
2115
--------------------------------------------------------------------}
2116

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

2120
  showConstraintHandler :: a -> IO String
2121

2122
  constrAttach :: Solver -> SomeConstraintHandler -> a -> IO Bool
2123

2124
  constrDetach :: Solver -> SomeConstraintHandler -> a -> IO ()
2125

2126
  constrIsLocked :: Solver -> SomeConstraintHandler -> a -> IO Bool
2127

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

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

2138
  constrOnUnassigned :: Solver -> SomeConstraintHandler -> a -> Lit -> IO ()
2139

2140
  isPBRepresentable :: a -> IO Bool
2141
  toPBLinAtLeast :: a -> IO PBLinAtLeast
2142

2143
  isSatisfied :: Solver -> a -> IO Bool
2144

2145
  constrIsProtected :: Solver -> a -> IO Bool
2146
  constrIsProtected _ _ = return False
×
2147

2148
  constrWeight :: Solver -> a -> IO Double
2149
  constrWeight _ _ = return 1.0
×
2150

2151
  constrReadActivity :: a -> IO Double
2152

2153
  constrWriteActivity :: a -> Double -> IO ()
2154

2155
attach :: Solver -> SomeConstraintHandler -> IO Bool
2156
attach solver c = constrAttach solver c c
1✔
2157

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

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

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

2193
isLocked :: Solver -> SomeConstraintHandler -> IO Bool
2194
isLocked solver c = constrIsLocked solver c c
×
2195

2196
data SomeConstraintHandler
2197
  = CHClause !ClauseHandler
2198
  | CHAtLeast !AtLeastHandler
2199
  | CHPBCounter !PBHandlerCounter
2200
  | CHPBPueblo !PBHandlerPueblo
2201
  | CHXORClause !XORClauseHandler
2202
  | CHTheory !TheoryHandler
2203
  deriving Eq
×
2204

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

2213
instance ConstraintHandler SomeConstraintHandler where
×
2214
  toConstraintHandler = id
1✔
2215

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

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

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

2237
  constrIsLocked solver this (CHClause c)    = constrIsLocked solver this c
×
2238
  constrIsLocked solver this (CHAtLeast c)   = constrIsLocked solver this c
×
2239
  constrIsLocked solver this (CHPBCounter c) = constrIsLocked solver this c
×
2240
  constrIsLocked solver this (CHPBPueblo c)  = constrIsLocked solver this c
×
2241
  constrIsLocked solver this (CHXORClause c) = constrIsLocked solver this c
×
2242
  constrIsLocked solver this (CHTheory c)    = constrIsLocked solver this c
×
2243

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

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

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

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

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

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

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

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

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

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

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

2349
    unIO (IO f) = f
1✔
2350
#endif
2351

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

2383
    unIO (IO f) = f
1✔
2384
#endif
2385

2386
{--------------------------------------------------------------------
2387
  Clause
2388
--------------------------------------------------------------------}
2389

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

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

2400
instance Eq ClauseHandler where
×
2401
  (==) = (==) `on` claLits
1✔
2402

2403
instance Hashable ClauseHandler where
2404
  hash = claHash
1✔
2405
  hashWithSalt = defaultHashWithSalt
1✔
2406

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

2413
instance ConstraintHandler ClauseHandler where
×
2414
  toConstraintHandler = CHClause
1✔
2415

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

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

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

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

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

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

2502
  constrPropagate !solver this this2 !falsifiedLit = do
1✔
2503
    preprocess
1✔
2504

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

2528
    where
2529
      a = claLits this2
1✔
2530

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

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

2548
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2549

2550
  isPBRepresentable _ = return True
1✔
2551

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

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

2562
  constrIsProtected _ this = do
×
2563
    size <- claGetSize this
×
2564
    return $! size <= 2
×
2565

2566
  constrReadActivity this = readIORef (claActivity this)
1✔
2567

2568
  constrWriteActivity this aval = writeIORef (claActivity this) $! aval
1✔
2569

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

2585
{--------------------------------------------------------------------
2586
  Cardinality Constraint
2587
--------------------------------------------------------------------}
2588

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

2597
instance Eq AtLeastHandler where
×
2598
  (==) = (==) `on` atLeastLits
×
2599

2600
instance Hashable AtLeastHandler where
2601
  hash = atLeastHash
1✔
2602
  hashWithSalt = defaultHashWithSalt
1✔
2603

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

2610
instance ConstraintHandler AtLeastHandler where
×
2611
  toConstraintHandler = CHAtLeast
1✔
2612

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

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

2623
    let a = atLeastLits this2
1✔
2624
    m <- getLitArraySize a
1✔
2625
    let n = atLeastNum this2
1✔
2626

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

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

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

2726
  constrPropagate solver this this2 falsifiedLit = do
1✔
2727
    preprocess
1✔
2728

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

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

2759
    where
2760
      a = atLeastLits this2
1✔
2761
      n = atLeastNum this2
1✔
2762

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

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

2807
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2808

2809
  isPBRepresentable _ = return True
1✔
2810

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

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

2826
  constrReadActivity this = readIORef (atLeastActivity this)
1✔
2827

2828
  constrWriteActivity this aval = writeIORef (atLeastActivity this) $! aval
1✔
2829

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

2845
{--------------------------------------------------------------------
2846
  Pseudo Boolean Constraint
2847
--------------------------------------------------------------------}
2848

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

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

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

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

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

2894
{--------------------------------------------------------------------
2895
  Pseudo Boolean Constraint (Counter)
2896
--------------------------------------------------------------------}
2897

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

2909
instance Eq PBHandlerCounter where
×
2910
  (==) = (==) `on` pbSlack
1✔
2911

2912
instance Hashable PBHandlerCounter where
2913
  hash = pbHash
1✔
2914
  hashWithSalt = defaultHashWithSalt
1✔
2915

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

2925
instance ConstraintHandler PBHandlerCounter where
×
2926
  toConstraintHandler = CHPBCounter
1✔
2927

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

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

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

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

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

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

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

3014
  isPBRepresentable _ = return True
1✔
3015

3016
  toPBLinAtLeast this = do
1✔
3017
    return (pbTerms this, pbDegree this)
1✔
3018

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

3027
  constrWeight _ _ = return 0.5
×
3028

3029
  constrReadActivity this = readIORef (pbActivity this)
1✔
3030

3031
  constrWriteActivity this aval = writeIORef (pbActivity this) $! aval
1✔
3032

3033
{--------------------------------------------------------------------
3034
  Pseudo Boolean Constraint (Pueblo)
3035
--------------------------------------------------------------------}
3036

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

3048
instance Eq PBHandlerPueblo where
×
3049
  (==) = (==) `on` puebloWatchSum
1✔
3050

3051
instance Hashable PBHandlerPueblo where
3052
  hash = puebloHash
1✔
3053
  hashWithSalt = defaultHashWithSalt
1✔
3054

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

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

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

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

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

3084
instance ConstraintHandler PBHandlerPueblo where
×
3085
  toConstraintHandler = CHPBPueblo
1✔
3086

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

3090
  constrAttach solver this this2 = do
1✔
3091
    bcpCheckEmpty solver
1✔
3092
    ret <- puebloPropagate solver this this2
1✔
3093

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

3113
    return ret
1✔
3114

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

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

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

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

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

3168
  isPBRepresentable _ = return True
1✔
3169

3170
  toPBLinAtLeast this = do
1✔
3171
    return (puebloTerms this, puebloDegree this)
1✔
3172

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

3181
  constrWeight _ _ = return 0.5
×
3182

3183
  constrReadActivity this = readIORef (puebloActivity this)
1✔
3184

3185
  constrWriteActivity this aval = writeIORef (puebloActivity this) $! aval
1✔
3186

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

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

3226
{--------------------------------------------------------------------
3227
  XOR Clause
3228
--------------------------------------------------------------------}
3229

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

3237
instance Eq XORClauseHandler where
×
3238
  (==) = (==) `on` xorLits
1✔
3239

3240
instance Hashable XORClauseHandler where
3241
  hash = xorHash
×
3242
  hashWithSalt = defaultHashWithSalt
×
3243

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

3250
instance ConstraintHandler XORClauseHandler where
×
3251
  toConstraintHandler = CHXORClause
1✔
3252

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

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

3262
    let a = xorLits this2
×
3263
    size <- getLitArraySize a
×
3264

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

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

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

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

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

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

3381
    where
3382
      v = litVar falsifiedLit
1✔
3383
      a = xorLits this2
1✔
3384

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

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

3413
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3414

3415
  isPBRepresentable _ = return False
1✔
3416

3417
  toPBLinAtLeast _ = error "XORClauseHandler does not support toPBLinAtLeast"
×
3418

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

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

3431
  constrReadActivity this = readIORef (xorActivity this)
1✔
3432

3433
  constrWriteActivity this aval = writeIORef (xorActivity this) $! aval
×
3434

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

3450
{--------------------------------------------------------------------
3451
  Arbitrary Boolean Theory
3452
--------------------------------------------------------------------}
3453

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

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

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

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

3497
data TheoryHandler = TheoryHandler deriving (Eq)
×
3498

3499
instance Hashable TheoryHandler where
3500
  hash _ = hash ()
×
3501
  hashWithSalt = defaultHashWithSalt
×
3502

3503
instance ConstraintHandler TheoryHandler where
×
3504
  toConstraintHandler = CHTheory
×
3505

3506
  showConstraintHandler _this = return "TheoryHandler"
×
3507

3508
  constrAttach _solver _this _this2 = error "TheoryHandler.constrAttach"
×
3509

3510
  constrDetach _solver _this _this2 = return ()
×
3511

3512
  constrIsLocked _solver _this _this2 = return True
×
3513

3514
  constrPropagate _solver _this _this2 _falsifiedLit =  error "TheoryHandler.constrPropagate"
×
3515

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

3521
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3522

UNCOV
3523
  isPBRepresentable _this = return False
×
3524

3525
  toPBLinAtLeast _this = error "TheoryHandler.toPBLinAtLeast"
×
3526

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

3529
  constrIsProtected _solver _this = error "TheoryHandler.constrIsProtected"
×
3530

3531
  constrReadActivity _this = return 0
1✔
3532

3533
  constrWriteActivity _this _aval = return ()
×
3534

3535
{--------------------------------------------------------------------
3536
  Restart strategy
3537
--------------------------------------------------------------------}
3538

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

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

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

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

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

3565
{-
3566
  Finite subsequences of the Luby-sequence:
3567

3568
  0: 1
3569
  1: 1 1 2
3570
  2: 1 1 2 1 1 2 4
3571
  3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
3572
  ...
3573

3574

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

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

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

3593

3594
{--------------------------------------------------------------------
3595
  utility
3596
--------------------------------------------------------------------}
3597

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

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

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

3624
#if !MIN_VERSION_hashable(1,4,3)
3625

3626
defaultHashWithSalt :: Hashable a => Int -> a -> Int
3627
defaultHashWithSalt salt x = salt `combine` hash x
3628
  where
3629
    combine :: Int -> Int -> Int
3630
    combine h1 h2 = (h1 * 16777619) `xor` h2
3631

3632
#endif
3633

3634
{--------------------------------------------------------------------
3635
  debug
3636
--------------------------------------------------------------------}
3637

3638
debugMode :: Bool
3639
debugMode = False
1✔
3640

3641
checkSatisfied :: Solver -> IO ()
3642
checkSatisfied solver = do
1✔
3643
  cls <- readIORef (svConstrDB solver)
1✔
3644
  forM_ cls $ \c -> do
1✔
3645
    b <- isSatisfied solver c
1✔
3646
    unless b $ do
×
3647
      s <- showConstraintHandler c
×
3648
      log solver $ "BUG: " ++ s ++ " is violated"
×
3649

3650
dumpVarActivity :: Solver -> IO ()
3651
dumpVarActivity solver = do
×
3652
  log solver "Variable activity:"
×
3653
  vs <- variables solver
×
3654
  forM_ vs $ \v -> do
×
3655
    activity <- varActivity solver v
×
3656
    log solver $ printf "activity(%d) = %d" v activity
×
3657

3658
dumpConstrActivity :: Solver -> IO ()
3659
dumpConstrActivity solver = do
×
3660
  log solver "Learnt constraints activity:"
×
3661
  xs <- learntConstraints solver
×
3662
  forM_ xs $ \c -> do
×
3663
    s <- showConstraintHandler c
×
3664
    aval <- constrReadActivity c
×
3665
    log solver $ printf "activity(%s) = %f" s aval
×
3666

3667
-- | set callback function for receiving messages.
3668
setLogger :: Solver -> (String -> IO ()) -> IO ()
3669
setLogger solver logger = do
×
3670
  writeIORef (svLogger solver) (Just logger)
×
3671

3672
-- | Clear logger function set by 'setLogger'.
3673
clearLogger :: Solver -> IO ()
3674
clearLogger solver = do
×
3675
  writeIORef (svLogger solver) Nothing
×
3676

3677
log :: Solver -> String -> IO ()
3678
log solver msg = logIO solver (return msg)
×
3679

3680
logIO :: Solver -> IO String -> IO ()
3681
logIO solver action = do
1✔
3682
  m <- readIORef (svLogger solver)
1✔
3683
  case m of
1✔
3684
    Nothing -> return ()
×
3685
    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

© 2025 Coveralls, Inc