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

msakai / toysolver / 767

22 May 2025 12:57PM UTC coverage: 71.847% (-0.06%) from 71.906%
767

push

github

web-flow
Merge f4d92f6d1 into c10d256d2

11104 of 15455 relevant lines covered (71.85%)

0.72 hits per line

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

74.45
/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
  -- ** Type-2 SOS constraints
85
  , addSOS2
86
  , evalSOS2
87
  -- ** Theory
88
  , setTheory
89

90
  -- * Solving
91
  , solve
92
  , solveWith
93
  , BudgetExceeded (..)
94
  , cancel
95
  , Canceled (..)
96

97
  -- * Extract results
98
  , IModel (..)
99
  , Model
100
  , getModel
101
  , getFailedAssumptions
102
  , getAssumptionsImplications
103

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

114
  -- * Callbacks
115
  , setLogger
116
  , clearLogger
117
  , setTerminateCallback
118
  , clearTerminateCallback
119
  , setLearnCallback
120
  , clearLearnCallback
121

122
  -- * Read state
123
  , getNVars
124
  , getNConstraints
125
  , getNLearntConstraints
126
  , getVarFixed
127
  , getLitFixed
128
  , getFixedLiterals
129

130
  -- * Internal API
131
  , varBumpActivity
132
  , varDecayActivity
133
  ) where
134

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

171
#ifdef __GLASGOW_HASKELL__
172
import GHC.Types (IO (..))
173
import GHC.Exts hiding (Constraint)
174
#endif
175

176
import ToySolver.Data.LBool
177
import ToySolver.SAT.Solver.CDCL.Config
178
import ToySolver.SAT.Types
179
import ToySolver.SAT.TheorySolver
180
import ToySolver.Internal.Util (revMapM)
181

182
{--------------------------------------------------------------------
183
  LitArray
184
--------------------------------------------------------------------}
185

186
newtype LitArray = LitArray (IOUArray Int PackedLit) deriving (Eq)
×
187

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

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

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

207
getLits :: LitArray -> IO [Lit]
208
getLits (LitArray a) = liftM (map unpackLit) $ getElems a
1✔
209

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

216
{--------------------------------------------------------------------
217
  internal data structures
218
--------------------------------------------------------------------}
219

220
type Level = Int
221

222
levelRoot :: Level
223
levelRoot = 0
1✔
224

225
litIndex :: Lit -> Int
226
litIndex l = 2 * (litVar l - 1) + (if litPolarity l then 1 else 0)
1✔
227

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

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

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

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

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

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

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

281
litLevel :: Solver -> Lit -> IO Level
282
litLevel solver l = varLevel solver (litVar l)
1✔
283

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

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

296
-- | Solver instance
297
data Solver
298
  = Solver
299
  { svOk           :: !(IORef Bool)
1✔
300

301
  , svVarQueue     :: !PQ.PriorityQueue
1✔
302
  , svTrail        :: !(Vec.UVec Lit)
1✔
303
  , svTrailLimit   :: !(Vec.UVec Lit)
1✔
304
  , svTrailNPropagated :: !(IOURef Int)
1✔
305

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

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

329
  , svConstrDB     :: !(IORef [SomeConstraintHandler])
1✔
330
  , svLearntDB     :: !(IORef (Int,[SomeConstraintHandler]))
1✔
331

332
  -- Theory
333
  , svTheorySolver  :: !(IORef (Maybe TheorySolver))
1✔
334
  , svTheoryChecked :: !(IOURef Int)
1✔
335

336
  -- Result
337
  , svModel        :: !(IORef (Maybe Model))
1✔
338
  , svFailedAssumptions :: !(IORef LitSet)
1✔
339
  , svAssumptionsImplications :: !(IORef LitSet)
1✔
340

341
  -- Statistics
342
  , svNDecision    :: !(IOURef Int)
1✔
343
  , svNRandomDecision :: !(IOURef Int)
1✔
344
  , svNConflict    :: !(IOURef Int)
1✔
345
  , svNRestart     :: !(IOURef Int)
1✔
346
  , svNLearntGC    :: !(IOURef Int)
1✔
347
  , svNRemovedConstr :: !(IOURef Int)
1✔
348

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

356
  -- Logging
357
  , svLogger :: !(IORef (Maybe (String -> IO ())))
1✔
358
  , svStartWC    :: !(IORef TimeSpec)
1✔
359
  , svLastStatWC :: !(IORef TimeSpec)
1✔
360

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

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

373
  -- | Amount to bump next constraint with.
374
  , svConstrInc    :: !(IOURef Double)
1✔
375

376
  -- ERWA / LRB
377

378
  -- | step-size parameter α
379
  , svERWAStepSize :: !(IOURef Double)
1✔
380
  , svEMAScale :: !(IOURef Double)
1✔
381
  , svLearntCounter :: !(IOURef Int)
1✔
382
  }
383

384
markBad :: Solver -> IO ()
385
markBad solver = do
1✔
386
  writeIORef (svOk solver) False
1✔
387
  bcpClear solver
1✔
388

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

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

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

413
bcpClear :: Solver -> IO ()
414
bcpClear solver = do
1✔
415
  m <- Vec.getSize (svTrail solver)
1✔
416
  writeIOURef (svTrailNPropagated solver) m
1✔
417

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

426
assign :: Solver -> Lit -> IO Bool
427
assign solver lit = assign_ solver lit Nothing
1✔
428

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

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

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

448
    Vec.push (svTrail solver) lit
1✔
449

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

456
    return True
1✔
457

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

463
  flag <- configEnablePhaseSaving <$> getConfig solver
1✔
464
  when flag $ Vec.unsafeWrite (svVarPolarity solver) (v - 1) $! fromJust (unliftBool val)
1✔
465

466
  Vec.unsafeWrite (svVarValue solver) (v - 1) (coerce lUndef)
1✔
467
  Vec.unsafeWrite (svVarTrailIndex solver) (v - 1) maxBound
1✔
468
  Vec.unsafeWrite (svVarLevel solver) (v - 1) maxBound
1✔
469
  Vec.unsafeWrite (svVarReason solver) (v - 1) Nothing
×
470

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

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

495
  PQ.enqueue (svVarQueue solver) v
1✔
496

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

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

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

511
unwatchLit :: Solver -> Lit -> SomeConstraintHandler -> IO ()
512
unwatchLit solver !lit c = Vec.unsafeModify (svLitWatches solver) (litIndex lit) (delete c)
1✔
513

514
unwatchVar :: Solver -> Lit -> SomeConstraintHandler -> IO ()
515
unwatchVar solver !var c = Vec.unsafeModify (svVarWatches solver) (var - 1) (delete c)
×
516

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

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

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

538
reduceDB :: Solver -> IO ()
539
reduceDB solver = do
1✔
540
  (_,cs) <- readIORef (svLearntDB solver)
1✔
541

542
  xs <- forM cs $ \c -> do
1✔
543
    p <- constrIsProtected solver c
×
544
    w <- constrWeight solver c
×
545
    actval <- constrReadActivity c
1✔
546
    return (c, (p, w*actval))
1✔
547

548
  -- Note that False <= True
549
  let ys = sortBy (comparing snd) xs
1✔
550
      (zs,ws) = splitAt (length ys `div` 2) ys
1✔
551

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

564
  let cs2 = zs2 ++ map fst ws
1✔
565
      n2 = length cs2
1✔
566

567
  -- log solver $ printf "learnt constraints deletion: %d -> %d" n n2
568
  writeIORef (svLearntDB solver) (n2,cs2)
1✔
569

570
type VarActivity = Double
571

572
varActivity :: Solver -> Var -> IO VarActivity
573
varActivity solver v = Vec.unsafeRead (svVarActivity solver) (v - 1)
1✔
574

575
varDecayActivity :: Solver -> IO ()
576
varDecayActivity solver = do
1✔
577
  d <- configVarDecay <$> getConfig solver
1✔
578
  modifyIOURef (svVarInc solver) (d*)
1✔
579

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

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

600
varEMAScaled :: Solver -> Var -> IO Double
601
varEMAScaled solver v = Vec.unsafeRead (svVarEMAScaled solver) (v - 1)
1✔
602

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

606
varIncrementReasoned :: Solver -> Var -> IO ()
607
varIncrementReasoned solver v = Vec.unsafeModify (svVarReasoned solver) (v - 1) (+1)
1✔
608

609
varEMADecay :: Solver -> IO ()
610
varEMADecay solver = do
1✔
611
  config <- getConfig solver
1✔
612

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

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

629
variables :: Solver -> IO [Var]
630
variables solver = do
×
631
  n <- getNVars solver
×
632
  return [1 .. n]
×
633

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

638
-- | number of assigned
639
getNAssigned :: Solver -> IO Int
640
getNAssigned solver = Vec.getSize (svTrail solver)
1✔
641

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

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

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

659
{--------------------------------------------------------------------
660
  Solver
661
--------------------------------------------------------------------}
662

663
-- | Create a new 'Solver' instance.
664
newSolver :: IO Solver
665
newSolver = newSolverWithConfig def
1✔
666

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

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

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

704
  constrInc   <- newIOURef 1
1✔
705
  varInc   <- newIOURef 1
1✔
706

707
  configRef <- newIORef config
1✔
708

709
  learntLim       <- newIORef undefined
×
710
  learntLimAdjCnt <- newIORef (-1)
1✔
711
  learntLimSeq    <- newIORef undefined
×
712

713
  logger <- newIORef Nothing
1✔
714
  startWC    <- newIORef undefined
×
715
  lastStatWC <- newIORef undefined
×
716

717
  randgen  <- newIORef =<< Rand.create
1✔
718

719
  failed <- newIORef IS.empty
×
720
  implied <- newIORef IS.empty
×
721

722
  confBudget <- newIOURef (-1)
1✔
723
  terminateCallback <- newIORef Nothing
1✔
724
  learntCallback <- newIORef Nothing
1✔
725

726
  tsolver <- newIORef Nothing
1✔
727
  tchecked <- newIOURef 0
1✔
728

729
  seen <- Vec.new
1✔
730
  pbLearnt <- newIORef Nothing
×
731

732
  alpha <- newIOURef 0.4
1✔
733
  emaScale <- newIOURef 1.0
1✔
734
  learntCounter <- newIOURef 0
1✔
735

736
  let solver =
1✔
737
        Solver
1✔
738
        { svOk = ok
1✔
739
        , svVarQueue   = vqueue
1✔
740
        , svTrail      = trail
1✔
741
        , svTrailLimit = trail_lim
1✔
742
        , svTrailNPropagated = trail_nprop
1✔
743

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

759
        , svConstrDB   = db
1✔
760
        , svLearntDB   = db2
1✔
761

762
        -- Theory
763
        , svTheorySolver  = tsolver
1✔
764
        , svTheoryChecked = tchecked
1✔
765

766
        -- Result
767
        , svModel      = m
1✔
768
        , svFailedAssumptions = failed
1✔
769
        , svAssumptionsImplications = implied
1✔
770

771
        -- Statistics
772
        , svNDecision  = ndecision
1✔
773
        , svNRandomDecision = nranddec
1✔
774
        , svNConflict  = nconflict
1✔
775
        , svNRestart   = nrestart
1✔
776
        , svNLearntGC  = nlearntgc
1✔
777
        , svNRemovedConstr = nremoved
1✔
778

779
        -- Configulation
780
        , svConfig     = configRef
1✔
781
        , svRandomGen  = randgen
1✔
782
        , svConfBudget = confBudget
1✔
783
        , svTerminateCallback = terminateCallback
1✔
784
        , svLearnCallback = learntCallback
1✔
785

786
        -- Logging
787
        , svLogger = logger
1✔
788
        , svStartWC    = startWC
1✔
789
        , svLastStatWC = lastStatWC
1✔
790

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

802
        , svERWAStepSize = alpha
1✔
803
        , svEMAScale = emaScale
1✔
804
        , svLearntCounter = learntCounter
1✔
805
        }
806
 return solver
1✔
807

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

821
{--------------------------------------------------------------------
822
  Problem specification
823
--------------------------------------------------------------------}
824

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

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

848
    Vec.push (svLitWatches solver) []
1✔
849
    Vec.push (svLitWatches solver) []
1✔
850
    Vec.push (svLitOccurList solver) HashSet.empty
1✔
851
    Vec.push (svLitOccurList solver) HashSet.empty
1✔
852

853
    PQ.enqueue (svVarQueue solver) v
1✔
854
    Vec.push (svSeen solver) False
1✔
855
    return v
1✔
856

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

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

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

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

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

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

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

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

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

965
    ok <- readIORef (svOk solver)
1✔
966
    when ok $ do
1✔
967
      (ts',n') <- liftM normalizePBLinAtLeast $ instantiatePBLinAtLeast (getLitFixed solver) (ts,n)
1✔
968

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

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

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

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

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

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

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

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

1043
{--------------------------------------------------------------------
1044
  Problem solving
1045
--------------------------------------------------------------------}
1046

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

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

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

1071
  log solver "Solving starts ..."
×
1072
  resetStat solver
1✔
1073
  writeIORef (svCanceled solver) False
1✔
1074
  writeIORef (svModel solver) Nothing
×
1075
  writeIORef (svFailedAssumptions solver) IS.empty
1✔
1076

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

1085
    nv <- getNVars solver
1✔
1086
    Vec.resizeCapacity (svTrail solver) nv
1✔
1087

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

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

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

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

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

1135
    printStatHeader solver
1✔
1136

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

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

1157
    backtrackTo solver levelRoot
1✔
1158

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

1171
    case result of
1✔
1172
      Right x  -> return x
1✔
1173
      Left m -> m
1✔
1174

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

1178
instance Exception BudgetExceeded
×
1179

1180
data Canceled = Canceled
1181
  deriving (Show, Typeable)
×
1182

1183
instance Exception Canceled
×
1184

1185
data SearchResult
1186
  = SRFinished Bool
1187
  | SRRestart
1188
  | SRBudgetExceeded
1189
  | SRCanceled
1190

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

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

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

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

1260
      modifyIOURef (svNConflict solver) (+1)
1✔
1261
      d <- getDecisionLevel solver
1✔
1262

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

1267
      modifyIORef' conflictCounter (+1)
1✔
1268
      c <- readIORef conflictCounter
1✔
1269

1270
      modifyIOURef (svConfBudget solver) $ \confBudget ->
1✔
1271
        if confBudget > 0 then confBudget - 1 else confBudget
×
1272
      confBudget <- readIOURef (svConfBudget solver)
1✔
1273

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

1282
      when (c `mod` 100 == 0) $ do
1✔
1283
        printStat solver False
1✔
1284

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

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

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

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

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

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

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

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

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

1394
{--------------------------------------------------------------------
1395
  Simplification
1396
--------------------------------------------------------------------}
1397

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

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

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

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

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

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

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

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

1495
{--------------------------------------------------------------------
1496
  Parameter settings.
1497
--------------------------------------------------------------------}
1498

1499
{--------------------------------------------------------------------
1500
  Configulation
1501
--------------------------------------------------------------------}
1502

1503
getConfig :: Solver -> IO Config
1504
getConfig solver = readIORef $ svConfig solver
1✔
1505

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

1513
modifyConfig :: Solver -> (Config -> Config) -> IO ()
1514
modifyConfig solver f = do
1✔
1515
  config <- getConfig solver
1✔
1516
  setConfig solver $ f config
1✔
1517

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

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

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

1530
setConfBudget :: Solver -> Maybe Int -> IO ()
1531
setConfBudget solver (Just b) | b >= 0 = writeIOURef (svConfBudget solver) b
×
1532
setConfBudget solver _ = writeIOURef (svConfBudget solver) (-1)
1✔
1533

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

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

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

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

1561
{--------------------------------------------------------------------
1562
  API for implementation of @solve@
1563
--------------------------------------------------------------------}
1564

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

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

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

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

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

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

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

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

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

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

1684
  pbConstrRef <- newIORef undefined
×
1685

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

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

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

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

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

1770
  lits2 <- minimizeConflictClause solver lits
1✔
1771

1772
  incrementReasoned solver (IS.toList lits2)
1✔
1773

1774
  xs <- liftM (sortBy (comparing (Down . snd))) $
1✔
1775
    forM (IS.toList lits2) $ \l -> do
1✔
1776
      lv <- litLevel solver l
1✔
1777
      return (l,lv)
1✔
1778

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1936
peekTrail :: Solver -> IO Lit
1937
peekTrail solver = do
1✔
1938
  n <- Vec.getSize (svTrail solver)
1✔
1939
  Vec.unsafeRead (svTrail solver) (n-1)
1✔
1940

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

1947
getDecisionLevel ::Solver -> IO Int
1948
getDecisionLevel solver = Vec.getSize (svTrailLimit solver)
1✔
1949

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

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

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

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

2003
saveAssumptionsImplications :: Solver -> IO ()
2004
saveAssumptionsImplications solver = do
1✔
2005
  n <- Vec.getSize (svAssumptions solver)
1✔
2006
  lv <- getDecisionLevel solver
1✔
2007

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

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

2027
constrDecayActivity :: Solver -> IO ()
2028
constrDecayActivity solver = do
1✔
2029
  d <- configConstrDecay <$> getConfig solver
1✔
2030
  modifyIOURef (svConstrInc solver) (d*)
1✔
2031

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

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

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

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

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

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

2101
    si :: Integer
2102
    si = fromIntegral (sec t)
×
2103

2104
    m :: Rational
2105
    m = s / 60
×
2106

2107
    mi :: Integer
2108
    mi = round m
×
2109

2110
    h :: Rational
2111
    h = m / 60
×
2112

2113
    hi :: Integer
2114
    hi = round h
×
2115

2116
{--------------------------------------------------------------------
2117
  constraint implementation
2118
--------------------------------------------------------------------}
2119

2120
class (Eq a, Hashable a) => ConstraintHandler a where
2121
  toConstraintHandler :: a -> SomeConstraintHandler
2122

2123
  showConstraintHandler :: a -> IO String
2124

2125
  constrAttach :: Solver -> SomeConstraintHandler -> a -> IO Bool
2126

2127
  constrDetach :: Solver -> SomeConstraintHandler -> a -> IO ()
2128

2129
  constrIsLocked :: Solver -> SomeConstraintHandler -> a -> IO Bool
2130

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

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

2141
  constrOnUnassigned :: Solver -> SomeConstraintHandler -> a -> Lit -> IO ()
2142

2143
  isPBRepresentable :: a -> IO Bool
2144
  toPBLinAtLeast :: a -> IO PBLinAtLeast
2145

2146
  isSatisfied :: Solver -> a -> IO Bool
2147

2148
  constrIsProtected :: Solver -> a -> IO Bool
2149
  constrIsProtected _ _ = return False
×
2150

2151
  constrWeight :: Solver -> a -> IO Double
2152
  constrWeight _ _ = return 1.0
1✔
2153

2154
  constrReadActivity :: a -> IO Double
2155

2156
  constrWriteActivity :: a -> Double -> IO ()
2157

2158
attach :: Solver -> SomeConstraintHandler -> IO Bool
2159
attach solver c = constrAttach solver c c
1✔
2160

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

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

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

2196
isLocked :: Solver -> SomeConstraintHandler -> IO Bool
2197
isLocked solver c = constrIsLocked solver c c
×
2198

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

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

2216
instance ConstraintHandler SomeConstraintHandler where
1✔
2217
  toConstraintHandler = id
1✔
2218

2219
  showConstraintHandler (CHClause c)    = showConstraintHandler c
×
2220
  showConstraintHandler (CHAtLeast c)   = showConstraintHandler c
×
2221
  showConstraintHandler (CHPBCounter c) = showConstraintHandler c
×
2222
  showConstraintHandler (CHPBPueblo c)  = showConstraintHandler c
×
2223
  showConstraintHandler (CHXORClause c) = showConstraintHandler c
×
2224
  showConstraintHandler (CHTheory c)    = showConstraintHandler c
×
2225

2226
  constrAttach solver this (CHClause c)    = constrAttach solver this c
×
2227
  constrAttach solver this (CHAtLeast c)   = constrAttach solver this c
×
2228
  constrAttach solver this (CHPBCounter c) = constrAttach solver this c
1✔
2229
  constrAttach solver this (CHPBPueblo c)  = constrAttach solver this c
1✔
2230
  constrAttach solver this (CHXORClause c) = constrAttach solver this c
×
2231
  constrAttach solver this (CHTheory c)    = constrAttach solver this c
×
2232

2233
  constrDetach solver this (CHClause c)    = constrDetach solver this c
1✔
2234
  constrDetach solver this (CHAtLeast c)   = constrDetach solver this c
×
2235
  constrDetach solver this (CHPBCounter c) = constrDetach solver this c
1✔
2236
  constrDetach solver this (CHPBPueblo c)  = constrDetach solver this c
1✔
2237
  constrDetach solver this (CHXORClause c) = constrDetach solver this c
×
2238
  constrDetach solver this (CHTheory c)    = constrDetach solver this c
×
2239

2240
  constrIsLocked solver this (CHClause c)    = constrIsLocked solver this c
×
2241
  constrIsLocked solver this (CHAtLeast c)   = constrIsLocked solver this c
×
2242
  constrIsLocked solver this (CHPBCounter c) = constrIsLocked solver this c
×
2243
  constrIsLocked solver this (CHPBPueblo c)  = constrIsLocked solver this c
×
2244
  constrIsLocked solver this (CHXORClause c) = constrIsLocked solver this c
×
2245
  constrIsLocked solver this (CHTheory c)    = constrIsLocked solver this c
×
2246

2247
  constrPropagate solver this (CHClause c)  lit   = constrPropagate solver this c lit
1✔
2248
  constrPropagate solver this (CHAtLeast c) lit   = constrPropagate solver this c lit
1✔
2249
  constrPropagate solver this (CHPBCounter c) lit = constrPropagate solver this c lit
1✔
2250
  constrPropagate solver this (CHPBPueblo c) lit  = constrPropagate solver this c lit
1✔
2251
  constrPropagate solver this (CHXORClause c) lit = constrPropagate solver this c lit
1✔
2252
  constrPropagate solver this (CHTheory c) lit    = constrPropagate solver this c lit
×
2253

2254
  constrReasonOf solver (CHClause c)  l   = constrReasonOf solver c l
×
2255
  constrReasonOf solver (CHAtLeast c) l   = constrReasonOf solver c l
1✔
2256
  constrReasonOf solver (CHPBCounter c) l = constrReasonOf solver c l
1✔
2257
  constrReasonOf solver (CHPBPueblo c) l  = constrReasonOf solver c l
1✔
2258
  constrReasonOf solver (CHXORClause c) l = constrReasonOf solver c l
1✔
2259
  constrReasonOf solver (CHTheory c) l    = constrReasonOf solver c l
×
2260

2261
  constrOnUnassigned solver this (CHClause c)  l   = constrOnUnassigned solver this c l
×
2262
  constrOnUnassigned solver this (CHAtLeast c) l   = constrOnUnassigned solver this c l
×
2263
  constrOnUnassigned solver this (CHPBCounter c) l = constrOnUnassigned solver this c l
×
2264
  constrOnUnassigned solver this (CHPBPueblo c) l  = constrOnUnassigned solver this c l
1✔
2265
  constrOnUnassigned solver this (CHXORClause c) l = constrOnUnassigned solver this c l
×
2266
  constrOnUnassigned solver this (CHTheory c) l    = constrOnUnassigned solver this c l
×
2267

2268
  isPBRepresentable (CHClause c)    = isPBRepresentable c
×
2269
  isPBRepresentable (CHAtLeast c)   = isPBRepresentable c
×
2270
  isPBRepresentable (CHPBCounter c) = isPBRepresentable c
×
2271
  isPBRepresentable (CHPBPueblo c)  = isPBRepresentable c
×
2272
  isPBRepresentable (CHXORClause c) = isPBRepresentable c
×
2273
  isPBRepresentable (CHTheory c)    = isPBRepresentable c
×
2274

2275
  toPBLinAtLeast (CHClause c)    = toPBLinAtLeast c
1✔
2276
  toPBLinAtLeast (CHAtLeast c)   = toPBLinAtLeast c
1✔
2277
  toPBLinAtLeast (CHPBCounter c) = toPBLinAtLeast c
1✔
2278
  toPBLinAtLeast (CHPBPueblo c)  = toPBLinAtLeast c
1✔
2279
  toPBLinAtLeast (CHXORClause c) = toPBLinAtLeast c
×
2280
  toPBLinAtLeast (CHTheory c)    = toPBLinAtLeast c
×
2281

2282
  isSatisfied solver (CHClause c)    = isSatisfied solver c
1✔
2283
  isSatisfied solver (CHAtLeast c)   = isSatisfied solver c
1✔
2284
  isSatisfied solver (CHPBCounter c) = isSatisfied solver c
1✔
2285
  isSatisfied solver (CHPBPueblo c)  = isSatisfied solver c
1✔
2286
  isSatisfied solver (CHXORClause c) = isSatisfied solver c
1✔
2287
  isSatisfied solver (CHTheory c)    = isSatisfied solver c
×
2288

2289
  constrIsProtected solver (CHClause c)    = constrIsProtected solver c
×
2290
  constrIsProtected solver (CHAtLeast c)   = constrIsProtected solver c
×
2291
  constrIsProtected solver (CHPBCounter c) = constrIsProtected solver c
×
2292
  constrIsProtected solver (CHPBPueblo c)  = constrIsProtected solver c
×
2293
  constrIsProtected solver (CHXORClause c) = constrIsProtected solver c
×
2294
  constrIsProtected solver (CHTheory c)    = constrIsProtected solver c
×
2295

2296
  constrReadActivity (CHClause c)    = constrReadActivity c
1✔
2297
  constrReadActivity (CHAtLeast c)   = constrReadActivity c
1✔
2298
  constrReadActivity (CHPBCounter c) = constrReadActivity c
1✔
2299
  constrReadActivity (CHPBPueblo c)  = constrReadActivity c
1✔
2300
  constrReadActivity (CHXORClause c) = constrReadActivity c
1✔
2301
  constrReadActivity (CHTheory c)    = constrReadActivity c
×
2302

2303
  constrWriteActivity (CHClause c)    aval = constrWriteActivity c aval
1✔
2304
  constrWriteActivity (CHAtLeast c)   aval = constrWriteActivity c aval
1✔
2305
  constrWriteActivity (CHPBCounter c) aval = constrWriteActivity c aval
1✔
2306
  constrWriteActivity (CHPBPueblo c)  aval = constrWriteActivity c aval
1✔
2307
  constrWriteActivity (CHXORClause c) aval = constrWriteActivity c aval
×
2308
  constrWriteActivity (CHTheory c)    aval = constrWriteActivity c aval
×
2309

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

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

2352
    unIO (IO f) = f
1✔
2353
#endif
2354

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

2386
    unIO (IO f) = f
1✔
2387
#endif
2388

2389
{--------------------------------------------------------------------
2390
  Clause
2391
--------------------------------------------------------------------}
2392

2393
data ClauseHandler
2394
  = ClauseHandler
2395
  { claLits :: !LitArray
1✔
2396
  , claActivity :: !(IORef Double)
1✔
2397
  , claHash :: !Int
1✔
2398
  }
2399

2400
claGetSize :: ClauseHandler -> IO Int
2401
claGetSize cla = getLitArraySize (claLits cla)
1✔
2402

2403
instance Eq ClauseHandler where
×
2404
  (==) = (==) `on` claLits
1✔
2405

2406
instance Hashable ClauseHandler where
2407
  hash = claHash
1✔
2408
  hashWithSalt = defaultHashWithSalt
1✔
2409

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

2416
instance ConstraintHandler ClauseHandler where
×
2417
  toConstraintHandler = CHClause
1✔
2418

2419
  showConstraintHandler this = do
×
2420
    lits <- getLits (claLits this)
×
2421
    return (show lits)
×
2422

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

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

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

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

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

2505
  constrPropagate !solver this this2 !falsifiedLit = do
1✔
2506
    preprocess
1✔
2507

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

2531
    where
2532
      a = claLits this2
1✔
2533

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

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

2551
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2552

2553
  isPBRepresentable _ = return True
1✔
2554

2555
  toPBLinAtLeast this = do
1✔
2556
    lits <- getLits (claLits this)
1✔
2557
    return ([(1,l) | l <- lits], 1)
1✔
2558

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

2565
  constrIsProtected _ this = do
1✔
2566
    size <- claGetSize this
1✔
2567
    return $! size <= 2
1✔
2568

2569
  constrReadActivity this = readIORef (claActivity this)
1✔
2570

2571
  constrWriteActivity this aval = writeIORef (claActivity this) $! aval
1✔
2572

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

2588
{--------------------------------------------------------------------
2589
  Cardinality Constraint
2590
--------------------------------------------------------------------}
2591

2592
data AtLeastHandler
2593
  = AtLeastHandler
2594
  { atLeastLits :: !LitArray
1✔
2595
  , atLeastNum :: !Int
1✔
2596
  , atLeastActivity :: !(IORef Double)
1✔
2597
  , atLeastHash :: !Int
×
2598
  }
2599

2600
instance Eq AtLeastHandler where
×
2601
  (==) = (==) `on` atLeastLits
×
2602

2603
instance Hashable AtLeastHandler where
2604
  hash = atLeastHash
×
2605
  hashWithSalt = defaultHashWithSalt
×
2606

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

2613
instance ConstraintHandler AtLeastHandler where
×
2614
  toConstraintHandler = CHAtLeast
1✔
2615

2616
  showConstraintHandler this = do
×
2617
    lits <- getLits (atLeastLits this)
×
2618
    return $ show lits ++ " >= " ++ show (atLeastNum this)
×
2619

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

2626
    let a = atLeastLits this2
1✔
2627
    m <- getLitArraySize a
1✔
2628
    let n = atLeastNum this2
1✔
2629

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

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

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

2729
  constrPropagate solver this this2 falsifiedLit = do
1✔
2730
    preprocess
1✔
2731

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

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

2762
    where
2763
      a = atLeastLits this2
1✔
2764
      n = atLeastNum this2
1✔
2765

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

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

2810
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
2811

2812
  isPBRepresentable _ = return True
1✔
2813

2814
  toPBLinAtLeast this = do
1✔
2815
    lits <- getLits (atLeastLits this)
1✔
2816
    return ([(1,l) | l <- lits], fromIntegral (atLeastNum this))
1✔
2817

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

2829
  constrReadActivity this = readIORef (atLeastActivity this)
1✔
2830

2831
  constrWriteActivity this aval = writeIORef (atLeastActivity this) $! aval
1✔
2832

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

2848
{--------------------------------------------------------------------
2849
  Pseudo Boolean Constraint
2850
--------------------------------------------------------------------}
2851

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

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

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

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

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

2897
{--------------------------------------------------------------------
2898
  Pseudo Boolean Constraint (Counter)
2899
--------------------------------------------------------------------}
2900

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

2912
instance Eq PBHandlerCounter where
×
2913
  (==) = (==) `on` pbSlack
1✔
2914

2915
instance Hashable PBHandlerCounter where
2916
  hash = pbHash
1✔
2917
  hashWithSalt = defaultHashWithSalt
1✔
2918

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

2928
instance ConstraintHandler PBHandlerCounter where
×
2929
  toConstraintHandler = CHPBCounter
1✔
2930

2931
  showConstraintHandler this = do
×
2932
    return $ show (pbTerms this) ++ " >= " ++ show (pbDegree this)
×
2933

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

2958
  constrDetach solver this this2 = do
1✔
2959
    forM_ (pbTerms this2) $ \(_,l) -> do
1✔
2960
      unwatchLit solver l this
1✔
2961

2962
  constrIsLocked solver this this2 = do
1✔
2963
    anyM (\(_,l) -> isReasonOf solver this l) (pbTerms this2)
×
2964

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

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

3013
  constrOnUnassigned _solver _this this2 lit = do
1✔
3014
    let c = pbCoeffMap this2 IM.! (- lit)
1✔
3015
    modifyIORef' (pbSlack this2) (+ c)
1✔
3016

3017
  isPBRepresentable _ = return True
1✔
3018

3019
  toPBLinAtLeast this = do
1✔
3020
    return (pbTerms this, pbDegree this)
1✔
3021

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

3030
  constrWeight _ _ = return 0.5
×
3031

3032
  constrReadActivity this = readIORef (pbActivity this)
1✔
3033

3034
  constrWriteActivity this aval = writeIORef (pbActivity this) $! aval
1✔
3035

3036
{--------------------------------------------------------------------
3037
  Pseudo Boolean Constraint (Pueblo)
3038
--------------------------------------------------------------------}
3039

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

3051
instance Eq PBHandlerPueblo where
×
3052
  (==) = (==) `on` puebloWatchSum
1✔
3053

3054
instance Hashable PBHandlerPueblo where
3055
  hash = puebloHash
1✔
3056
  hashWithSalt = defaultHashWithSalt
1✔
3057

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

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

3073
puebloGetWatchSum :: PBHandlerPueblo -> IO Integer
3074
puebloGetWatchSum pb = readIORef (puebloWatchSum pb)
1✔
3075

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

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

3087
instance ConstraintHandler PBHandlerPueblo where
×
3088
  toConstraintHandler = CHPBPueblo
1✔
3089

3090
  showConstraintHandler this = do
×
3091
    return $ show (puebloTerms this) ++ " >= " ++ show (puebloDegree this)
×
3092

3093
  constrAttach solver this this2 = do
1✔
3094
    bcpCheckEmpty solver
1✔
3095
    ret <- puebloPropagate solver this this2
1✔
3096

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

3116
    return ret
1✔
3117

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

3123
  constrIsLocked solver this this2 = do
1✔
3124
    anyM (\(_,l) -> isReasonOf solver this l) (puebloTerms this2)
×
3125

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

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

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

3171
  isPBRepresentable _ = return True
1✔
3172

3173
  toPBLinAtLeast this = do
1✔
3174
    return (puebloTerms this, puebloDegree this)
1✔
3175

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

3184
  constrWeight _ _ = return 0.5
×
3185

3186
  constrReadActivity this = readIORef (puebloActivity this)
1✔
3187

3188
  constrWriteActivity this aval = writeIORef (puebloActivity this) $! aval
1✔
3189

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

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

3229
{--------------------------------------------------------------------
3230
  XOR Clause
3231
--------------------------------------------------------------------}
3232

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

3240
instance Eq XORClauseHandler where
×
3241
  (==) = (==) `on` xorLits
1✔
3242

3243
instance Hashable XORClauseHandler where
3244
  hash = xorHash
×
3245
  hashWithSalt = defaultHashWithSalt
×
3246

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

3253
instance ConstraintHandler XORClauseHandler where
×
3254
  toConstraintHandler = CHXORClause
1✔
3255

3256
  showConstraintHandler this = do
×
3257
    lits <- getLits (xorLits this)
×
3258
    return ("XOR " ++ show lits)
×
3259

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

3265
    let a = xorLits this2
×
3266
    size <- getLitArraySize a
×
3267

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

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

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

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

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

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

3384
    where
3385
      v = litVar falsifiedLit
1✔
3386
      a = xorLits this2
1✔
3387

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

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

3416
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3417

3418
  isPBRepresentable _ = return False
1✔
3419

3420
  toPBLinAtLeast _ = error "XORClauseHandler does not support toPBLinAtLeast"
×
3421

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

3430
  constrIsProtected _ this = do
×
3431
    size <- getLitArraySize (xorLits this)
×
3432
    return $! size <= 2
×
3433

3434
  constrReadActivity this = readIORef (xorActivity this)
1✔
3435

3436
  constrWriteActivity this aval = writeIORef (xorActivity this) $! aval
×
3437

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

3453
{--------------------------------------------------------------------
3454
  Arbitrary Boolean Theory
3455
--------------------------------------------------------------------}
3456

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

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

3473
getTheory :: Solver -> IO (Maybe TheorySolver)
3474
getTheory solver = readIORef (svTheorySolver solver)
1✔
3475

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

3500
data TheoryHandler = TheoryHandler deriving (Eq)
×
3501

3502
instance Hashable TheoryHandler where
3503
  hash _ = hash ()
×
3504
  hashWithSalt = defaultHashWithSalt
×
3505

3506
instance ConstraintHandler TheoryHandler where
×
3507
  toConstraintHandler = CHTheory
×
3508

3509
  showConstraintHandler _this = return "TheoryHandler"
×
3510

3511
  constrAttach _solver _this _this2 = error "TheoryHandler.constrAttach"
×
3512

3513
  constrDetach _solver _this _this2 = return ()
×
3514

3515
  constrIsLocked _solver _this _this2 = return True
×
3516

3517
  constrPropagate _solver _this _this2 _falsifiedLit =  error "TheoryHandler.constrPropagate"
×
3518

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

3524
  constrOnUnassigned _solver _this _this2 _lit = return ()
×
3525

3526
  isPBRepresentable _this = return False
1✔
3527

3528
  toPBLinAtLeast _this = error "TheoryHandler.toPBLinAtLeast"
×
3529

3530
  isSatisfied _solver _this = error "TheoryHandler.isSatisfied"
×
3531

3532
  constrIsProtected _solver _this = error "TheoryHandler.constrIsProtected"
×
3533

3534
  constrReadActivity _this = return 0
1✔
3535

3536
  constrWriteActivity _this _aval = return ()
×
3537

3538
{--------------------------------------------------------------------
3539
  Restart strategy
3540
--------------------------------------------------------------------}
3541

3542
mkRestartSeq :: RestartStrategy -> Int -> Double -> [Int]
3543
mkRestartSeq MiniSATRestarts = miniSatRestartSeq
1✔
3544
mkRestartSeq ArminRestarts   = arminRestartSeq
1✔
3545
mkRestartSeq LubyRestarts    = lubyRestartSeq
1✔
3546

3547
miniSatRestartSeq :: Int -> Double -> [Int]
3548
miniSatRestartSeq start inc = iterate (ceiling . (inc *) . fromIntegral) start
1✔
3549

3550
{-
3551
miniSatRestartSeq :: Int -> Double -> [Int]
3552
miniSatRestartSeq start inc = map round $ iterate (inc*) (fromIntegral start)
3553
-}
3554

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

3565
lubyRestartSeq :: Int -> Double -> [Int]
3566
lubyRestartSeq start inc = map (ceiling . (fromIntegral start *) . luby inc) [0..]
1✔
3567

3568
{-
3569
  Finite subsequences of the Luby-sequence:
3570

3571
  0: 1
3572
  1: 1 1 2
3573
  2: 1 1 2 1 1 2 4
3574
  3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
3575
  ...
3576

3577

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

3586
    go :: Integer -> Integer -> (Integer, Integer)
3587
    go size sequ
1✔
3588
      | size < x+1 = go (2*size+1) (sequ+1)
1✔
3589
      | otherwise  = (size, sequ)
×
3590

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

3596

3597
{--------------------------------------------------------------------
3598
  utility
3599
--------------------------------------------------------------------}
3600

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

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

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

3627
#if !MIN_VERSION_hashable(1,4,3)
3628

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

3635
#endif
3636

3637
{--------------------------------------------------------------------
3638
  debug
3639
--------------------------------------------------------------------}
3640

3641
debugMode :: Bool
3642
debugMode = False
1✔
3643

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

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

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

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

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

3680
log :: Solver -> String -> IO ()
3681
log solver msg = logIO solver (return msg)
×
3682

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