├── .gitattributes ├── .gitignore ├── App.config ├── Bit.fs ├── BitVector.fs ├── BitVectorValuation.fs ├── BooleanValuation.fs ├── BoundInference.fs ├── BoundsOperations.fs ├── BoundsTheory.fs ├── BoundsValuation.fs ├── Clause.fs ├── ClauseDB.fs ├── ConflictRules.fs ├── DataBase.fs ├── DecisionRules.fs ├── Explain.fs ├── GlobalOptions.fs ├── InitializationRules.fs ├── Interval.fs ├── LICENSE.txt ├── Learning.fs ├── Literal.fs ├── Main.fs ├── Makefile ├── Model.fs ├── ModelVerification.fs ├── Numeral.fs ├── NumeralDB.fs ├── Preprocessing.fs ├── PriorityQueue.fs ├── Problem.fs ├── PropagationRules.fs ├── README.md ├── RLEBVOperations.fs ├── RLEBVTheory.fs ├── Rules.fs ├── SECURITY.md ├── SandboxState.fs ├── Solver.fs ├── State.fs ├── Stats.fs ├── TheoryDB.fs ├── TheoryRelation.fs ├── Trail.fs ├── Util.fs ├── VariableDB.fs ├── VariableOrder.fs ├── WatchManager.fs ├── Z3Check.fs ├── issues └── gh1 │ ├── gh1-2.smt2 │ ├── gh1-simp.smt2 │ └── gh1.smt2 ├── mcBV-mono.fsproj ├── mcBV.fsproj ├── mcBV.sln ├── packages.config ├── tests ├── bogus_implication.smt2 ├── bogus_implication2.smt2 ├── boolprop.smt2 ├── bvadd-unsat.smt2 ├── bvadd.smt2 ├── bvdiv.smt2 ├── concat1.smt2 ├── concat2.smt2 ├── sdiv1.smt2 ├── sle1.smt2 ├── sle2.smt2 ├── sle3.smt2 ├── slt1-unsat.smt2 ├── slt1.smt2 ├── slt2-unsat.smt2 ├── slt2.smt2 ├── slt3-unsat.smt2 ├── slt3.smt2 ├── slt4.smt2 ├── soundness1.smt2 ├── udiv1.smt2 ├── udiv2.smt2 ├── uge.smt2 ├── ugt.smt2 ├── ule.smt2 ├── ule1.smt2 └── ult.smt2 ├── z3-mono └── README.md └── z3 └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | #packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | 158 | 159 | # mcBV specific 160 | .z3-trace 161 | packages 162 | tests/*.out 163 | z3/* 164 | z3-mono/* -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Bit.fs: -------------------------------------------------------------------------------- 1 | module Bit 2 | 3 | open System.Numerics 4 | open Util 5 | 6 | type Bit = 7 | | Zero 8 | | One 9 | | U 10 | | N // "Nothing" or "NotABit" 11 | 12 | override r.ToString() = 13 | match r with 14 | | Zero -> "0" 15 | | One -> "1" 16 | | U -> "U" 17 | | N -> "N" 18 | 19 | let bitFromInt (i:int64) = 20 | match i with 21 | | 0L -> Zero 22 | | 1L -> One 23 | | _ -> U 24 | 25 | let bitFromBigInt (i:BigInteger) = 26 | if i = BigInteger.Zero then 27 | Zero 28 | elif i = BigInteger.One then 29 | One 30 | else 31 | U 32 | 33 | let bitToString (b:Bit) = 34 | match b with 35 | | Zero -> "0" 36 | | One -> "1" 37 | | U -> "U" 38 | | N -> "N" 39 | 40 | let And (b1:Bit) (b2:Bit) = 41 | assert (b1 <> N && b2 <> N) 42 | if b1 = b2 then 43 | b1 44 | else if b1 = Zero || b2 = Zero then 45 | Zero 46 | else 47 | U 48 | 49 | let Or (b1:Bit) (b2:Bit) = 50 | assert (b1 <> N && b2 <> N) 51 | if b1 = b2 then 52 | b1 53 | else if b1 = One || b2 = One then 54 | One 55 | else 56 | U 57 | 58 | let XOr (b1:Bit) (b2:Bit) = 59 | assert (b1 <> N && b2 <> N) 60 | match (b1, b2) with 61 | | (Zero, Zero) 62 | | (One, One) -> Zero 63 | | (Zero, One) 64 | | (One, Zero) -> One 65 | | _ -> U 66 | 67 | let Add b1 b2 = XOr b1 b2 68 | 69 | let Not (b1:Bit) = 70 | assert (b1 <> N) 71 | match b1 with 72 | | One -> Zero 73 | | Zero -> One 74 | | U -> U 75 | | _ -> N 76 | 77 | let Intersect (b1:Bit) (b2:Bit) = 78 | assert (b1 <> N && b2 <> N) 79 | 80 | match (b1,b2) with 81 | | (N, _) 82 | | (_, N) 83 | | (One, Zero) 84 | | (Zero, One) -> //UNREACHABLE("CMW: Is Intersect really expected to return N bits?"); 85 | //AZ: Yes, that is how the outer function knows that it is not a valid bit-vector 86 | N 87 | | (U, _) -> b2 88 | | (_, U) -> b1 89 | | _ -> assert (b1=b2) 90 | b1 91 | 92 | let isConcrete (b:Bit) = 93 | (b = One || b = Zero) -------------------------------------------------------------------------------- /BitVectorValuation.fs: -------------------------------------------------------------------------------- 1 | module BitVectorValuation 2 | 3 | open Literal 4 | open BitVector 5 | 6 | type BitVectorValuation (size:int, sorts:VarType[]) = 7 | let mutable allocated = size + 1 8 | let mutable reallocCoefficient = 2.0 9 | 10 | member val inUse = size + 1 with get, set 11 | member val vals = [| for s in sorts do yield if s > 0 then (BitVector s) else BitVector.Invalid |] with get, set 12 | member val mAssignmntsExplanations = Array.create (size + 1) (0:Var) with get, set 13 | 14 | member val private inTempMode = false with get, set 15 | member val private snapshot = -1 with get, set 16 | 17 | member r.getInUse = r.inUse 18 | 19 | member r.reallocate() = 20 | let newSize = int (reallocCoefficient * float allocated) 21 | r.reallocate newSize 22 | 23 | member r.reallocate (newSize:int) = 24 | r.vals <- Array.append r.vals (Array.create ((newSize + 1) - allocated) (BitVector.Invalid) ) 25 | r.mAssignmntsExplanations <- Array.append r.mAssignmntsExplanations (Array.create ((newSize + 1) - allocated) 0) 26 | allocated <- r.vals.Length 27 | 28 | member r.fastForward (oInUse:int) (sorts: Ref) = 29 | if r.inUse < oInUse then 30 | if oInUse >= allocated then 31 | r.reallocate oInUse 32 | 33 | for i in r.inUse .. oInUse - 1 do 34 | r.newVar i (!sorts).[i] 35 | assert (r.inUse = oInUse) 36 | 37 | member r.newVar (var:Var) (s:VarType) = 38 | assert(var = r.inUse) 39 | if r.inUse = allocated then 40 | r.reallocate() 41 | r.inUse <- r.inUse + 1 42 | if (s <> 0) then 43 | let bv = BitVector s 44 | r.vals.[var] <- bv 45 | 46 | member private r.isBVVar (v:Var) = 47 | (v > 0 && v < r.inUse && r.vals.[v].Length <> 0) 48 | 49 | member private r.isBooleanVar (v:Var) = 50 | (v > 0 && v < r.inUse && r.vals.[v].Length = 0) 51 | 52 | member r.getValue (i:Var) = 53 | assert (r.isBVVar i) 54 | r.vals.[i] 55 | 56 | member r.isAssigned (i:Var) = 57 | if r.isBVVar i then 58 | r.vals.[i].isConcreteValue 59 | elif r.isBooleanVar i then 60 | false 61 | else 62 | true // Numerals have i < 0 and they are assigned by definition 63 | 64 | member r.isConcreteValue (i:Var) = 65 | assert (r.isBVVar i) 66 | r.vals.[i].isConcreteValue 67 | 68 | member r.setValue (i:Var) (bv:BitVector) = 69 | assert (r.isBVVar i) 70 | bv.CheckInvariant() 71 | // dbg <| (lazy sprintf " | new value: %d:bv = %s" i (bv.ToString())) 72 | r.vals.[i] <- bv 73 | 74 | member r.assignedVars = 75 | let mutable cnt = 0 76 | for i in 0 .. r.inUse do 77 | if r.isBVVar i && r.isConcreteValue i then 78 | cnt <- cnt + 1 79 | cnt 80 | 81 | member r.getExplanation (v:Var) = 82 | assert (0 <= v && v <= r.inUse) 83 | r.mAssignmntsExplanations.[v] 84 | member r.getMAssignmentExplRef = 85 | ref r.mAssignmntsExplanations 86 | 87 | member r.enterTempMode (orig:Ref) (sorts:Ref) = 88 | assert (not r.inTempMode ) 89 | assert (r.snapshot = -1) 90 | r.inTempMode <- true 91 | r.snapshot <- (!orig).getInUse 92 | r.fastForward r.snapshot sorts 93 | 94 | assert (r.inUse = (!orig).getInUse) 95 | assert (Array.fold (fun s (x:BitVector) -> s && (x.isFullyUndefined) ) true r.vals) 96 | assert (Array.fold (fun s (x:int) -> s && x = 0) true r.mAssignmntsExplanations ) 97 | for i in 1 .. r.inUse - 1 do 98 | assert (r.vals.[i].Length = (!sorts).[i]) 99 | assert (r.vals.[i].Length = (!orig).vals.[i].Length) 100 | 101 | 102 | 103 | // for i in 0 .. r.inUse do 104 | // assert (r.vals.[i].isFullyUndefined) 105 | 106 | 107 | member r.leaveTempMode = 108 | assert(r.inTempMode) 109 | assert(r.snapshot >= 0) 110 | for i in r.snapshot .. r.inUse - 1 do 111 | r.vals.[i] <- BitVector.Invalid 112 | r.mAssignmntsExplanations.[i] <- 0 113 | 114 | r.inUse <- r.snapshot 115 | r.snapshot <- -1 116 | r.inTempMode <- false -------------------------------------------------------------------------------- /BooleanValuation.fs: -------------------------------------------------------------------------------- 1 | module BooleanValuation 2 | 3 | open GlobalOptions 4 | open Literal 5 | 6 | type Val = 7 | | True 8 | | False 9 | | Undefined 10 | 11 | override r.ToString () : string = 12 | match r with 13 | | True -> "True" 14 | | False -> "False" 15 | | Undefined -> "Undef" 16 | 17 | member r.not :Val = 18 | match r with 19 | | True -> False 20 | | False -> True 21 | | Undefined -> Undefined 22 | 23 | 24 | 25 | let Not (v:Val) :Val = 26 | match v with 27 | | True -> False 28 | | False -> True 29 | | Undefined -> Undefined 30 | 31 | let consistent (x:Val) (y:Val) = 32 | match (x,y) with 33 | | (True, False) | (False, True) -> false 34 | | _ -> true 35 | 36 | type BooleanValuation(size:int) = 37 | 38 | let mutable allocated = size + 1 //1 to account for L 0 being reserved 39 | let mutable inUse = size + 1 40 | 41 | let mutable reallocCoefficient = 2.0 42 | 43 | member val valueB = Array.create allocated Undefined with get,set 44 | member val valueT = Array.create allocated Undefined with get,set 45 | member val booleanLevel = Array.create allocated -1 with get,set 46 | member val theoryLevel = Array.create allocated -1 with get,set 47 | 48 | member val private inTempMode = false with get, set 49 | member val private snapshot = -1 with get, set 50 | 51 | member r.getInUse = inUse 52 | 53 | member r.assignedVars = 54 | Array.sum (Array.map (fun x -> if x <> Undefined then 1 else 0) r.valueB) 55 | 56 | member r.isConsistent = 57 | Array.sum (Array.map2 (fun x y -> if consistent x y then 0 else 1) r.valueB r.valueT) 58 | 59 | member r.reallocate () = 60 | let newSize = int (reallocCoefficient * float allocated) 61 | r.reallocate newSize 62 | 63 | member r.reallocate (newSize:int) = 64 | assert (newSize >= allocated) 65 | r.valueB <- Array.append r.valueB (Array.create ((newSize + 1) - allocated) Undefined ) 66 | r.valueT <- Array.append r.valueT (Array.create ((newSize + 1) - allocated) Undefined ) 67 | r.booleanLevel <- Array.append r.booleanLevel (Array.create ((newSize + 1) - allocated) -1 ) 68 | r.theoryLevel <- Array.append r.theoryLevel (Array.create ((newSize + 1) - allocated) -1 ) 69 | allocated <- r.valueB.Length 70 | 71 | member r.newVar (var:Var) = 72 | assert(var = inUse) 73 | if inUse = allocated then 74 | r.reallocate() 75 | 76 | inUse <- inUse + 1 77 | 78 | 79 | member r.getValueB(l:Literal) = 80 | let v = lit2var l 81 | assert (v < inUse) 82 | if isNegated l then 83 | Not r.valueB.[v] 84 | else 85 | r.valueB.[v] 86 | 87 | member r.getValueT(l:Literal) = 88 | let v = lit2var l 89 | assert (v < inUse) 90 | if isNegated l then 91 | Not r.valueT.[v] 92 | else 93 | r.valueT.[v] 94 | 95 | member r.getBLvl(l:Literal) = 96 | let v = lit2var l 97 | assert (v < inUse) 98 | r.booleanLevel.[v] 99 | 100 | member r.getTLvl(l:Literal) = 101 | let v = lit2var l 102 | assert (v < inUse) 103 | r.theoryLevel.[v] 104 | 105 | member r.resetVal(l:Literal) = 106 | let v = lit2var l 107 | assert (v < inUse) 108 | r.valueB.[v] <- Undefined 109 | r.valueT.[v] <- Undefined 110 | r.booleanLevel.[v] <- -1 111 | //r.valueB.[v] 112 | 113 | member r.resetValueT (l:Literal) = 114 | let v = lit2var l 115 | assert (v < inUse) 116 | r.valueT.[v] <- Undefined 117 | r.theoryLevel.[v] <- -1 118 | 119 | member r.resetValueTAboveCurrentDecisionLevel (l:int) = 120 | for i in 1 .. inUse - 1 do 121 | if r.getTLvl i > l then 122 | r.resetValueT i 123 | 124 | 125 | member r.setValueB (l:Literal) (lvl:int)= 126 | let v = lit2var l 127 | assert (v < inUse) 128 | 129 | r.booleanLevel.[v] <- lvl 130 | 131 | if isNegated l then 132 | r.valueB.[v] <- False 133 | r.valueB.[v] 134 | else 135 | r.valueB.[v] <- True 136 | r.valueB.[v] 137 | 138 | member r.setValueT (l:Literal) (lvl:int) = 139 | let v = lit2var l 140 | assert (v < inUse) 141 | 142 | r.theoryLevel.[v] <- lvl 143 | 144 | if isNegated l then 145 | r.valueT.[v] <- False 146 | r.valueT.[v] 147 | else 148 | r.valueT.[v] <- True 149 | r.valueT.[v] 150 | 151 | member r.getFirstUndefVar () = 152 | let mutable i = 1 153 | while i < inUse && r.valueB.[i] <> Undefined do 154 | i <- i + 1 155 | 156 | if i < inUse then 157 | i 158 | else 159 | 0 160 | 161 | member r.enterTempMode (orig:Ref) = 162 | assert (not r.inTempMode ) 163 | assert (r.snapshot = -1) 164 | r.inTempMode <- true 165 | r.snapshot <- (!orig).getInUse 166 | r.fastForward r.snapshot 167 | 168 | assert (r.getInUse = (!orig).getInUse) 169 | assert (Array.fold (fun s x -> s && (x = Undefined)) true r.valueB) 170 | assert (Array.fold (fun s x -> s && (x = Undefined)) true r.valueT) 171 | assert (Array.fold (fun s x -> s && (x = -1)) true r.booleanLevel) 172 | assert (Array.fold (fun s x -> s && (x = -1)) true r.theoryLevel) 173 | 174 | member r.leaveTempMode = 175 | assert(r.inTempMode) 176 | assert(r.snapshot >= 0) 177 | for i in r.snapshot .. inUse - 1 do 178 | r.resetVal i 179 | r.resetValueT i 180 | 181 | inUse <- r.snapshot 182 | r.snapshot <- -1 183 | r.inTempMode <- false 184 | 185 | member private r.fastForward (oInUse:int) = 186 | if oInUse > allocated then 187 | r.reallocate oInUse 188 | if oInUse > inUse then 189 | inUse <- oInUse 190 | 191 | member r.getFirstUndefLit (sorts:Ref) = 192 | let mutable i = 1 193 | while i < inUse && (r.valueB.[i] <> Undefined || (!sorts).[i] > 0) do 194 | i <- i + 1 195 | 196 | if i < inUse then 197 | if DBG then 198 | i 199 | else 200 | // if (System.Random().Next() % 2) = 0 then 201 | // -i 202 | // else 203 | i 204 | else 205 | i <- 1 206 | while i < inUse && (!sorts).[i] = 0 do 207 | i <- i + 1 208 | if i < inUse then 209 | i 210 | else 211 | 0 212 | -------------------------------------------------------------------------------- /BoundInference.fs: -------------------------------------------------------------------------------- 1 | module BoundInference 2 | open System.Collections.Generic 3 | open Microsoft.Z3 4 | open GlobalOptions 5 | open Util 6 | open Numeral 7 | open Literal 8 | open BooleanValuation 9 | open Clause 10 | open Trail 11 | open State 12 | open WatchManager 13 | open VariableDB 14 | open ClauseDB 15 | open TheoryDB 16 | open ThRel 17 | open BitVector 18 | open BitVectorValuation 19 | open Explain 20 | open Learning 21 | 22 | // 1 Determine the relation 23 | // 2 Determine reverse operation 24 | // 3 Evaluate 25 | 26 | // 27 | //let inferByRelations (s:State) (v:int) (tRel:internalThRel) = 28 | // assert (List.exists (fun x -> x = v) tRel.distinctArgs) 29 | // 30 | // if tRel.getRhs 31 | 32 | // Assume" x_l,x_u <= op args_l args_u (rhs) 33 | // We will evaluate the op args_l args_u 34 | // And based on that update the x_l, x_u 35 | // rhs_l <= x_l <= x_u <= rhs_u 36 | // 37 | //let inferBounds (s:State) (v:int) (tRel:internalThRel) = 38 | // let (currentL, currentU) = (!s.partAssignment).getBounds v 39 | // if BitVector.bvEQ currentL currentU then 40 | // None 41 | // else 42 | // let (inferredL,inferredU) = inferByRelations s v tRel 43 | // 44 | // let resL = if not (BitVector.bvULEQ inferredL currentL) then 45 | // inferredL 46 | // else 47 | // currentL 48 | // 49 | // let resU = if not (BitVector.bvULEQ currentU inferredU) then 50 | // inferredU 51 | // else 52 | // currentU 53 | // Some (relL,resU) 54 | // 55 | // 56 | -------------------------------------------------------------------------------- /BoundsTheory.fs: -------------------------------------------------------------------------------- 1 | module BoundsTheory 2 | 3 | open Microsoft.Z3 4 | open GlobalOptions 5 | open Util 6 | open Numeral 7 | open Literal 8 | open BooleanValuation 9 | open BitVectorValuation 10 | open BoundsValuation 11 | open NumeralDB 12 | open Clause 13 | open Trail 14 | open State 15 | open TheoryRelation 16 | open BitVector 17 | open Learning 18 | open Interval 19 | open Z3Check 20 | open BoundsOperations 21 | 22 | type BoundType = 23 | | Lower 24 | | Upper 25 | | Interval 26 | 27 | // CMW: Global Note: All the functions in this file implement some bounds-specific 28 | // function. The idea is that they can reason over bounds _only_. Quick sanity check: 29 | // If one of the functions has a BitVectorEvaluation as an argument, it automatically 30 | // depends on RLEBVTheory, which we don't want. We rather want the Interval[] in 31 | // s.partAssignment.bounds 32 | // We can exploit the combination of the two theories later (e.g., in tDecide and 33 | // tGeneralize). For now, we can have all Boolean combinations of RLEBV constraints 34 | // (PAs) and bounds constraints (Intervals), which does not require any implementation 35 | // work, it will happen automatically once each of the theories has generated a few 36 | // clauses (over their theory only), and the Boolean engine starts to resolve them with 37 | // each other. 38 | // Further theory dependency check: change the order of RLEBVTheory.fs and 39 | // BoundsTheory.fs in the project, everything should compile regardless of the 40 | // order of those two files. 41 | 42 | let tbndsHolds (r:TheoryRelation) (pBounds:Ref) (pNumerals:Ref) = 43 | let relOp = 44 | (fun (xBnds:Interval) (yBnds:Interval) -> 45 | match r.getRelationOP with 46 | | Z3_decl_kind.Z3_OP_EQ when xBnds.isSingleton && yBnds.isSingleton -> 47 | if BitVector.bvEQ (xBnds.Singleton) (yBnds.Singleton) then True else False 48 | | Z3_decl_kind.Z3_OP_ULEQ when xBnds.isSingleton && yBnds.isSingleton -> 49 | if BitVector.bvULEQ (xBnds.Singleton) (yBnds.Singleton) then True else False 50 | | Z3_decl_kind.Z3_OP_EQ -> 51 | if (xBnds.isSingleton) then 52 | if not (yBnds.Contains(xBnds.Singleton)) then False else Undefined 53 | elif (yBnds.isSingleton) then 54 | if not (xBnds.Contains(yBnds.Singleton)) then False else Undefined 55 | else 56 | Undefined 57 | | Z3_decl_kind.Z3_OP_ULEQ -> 58 | if (BitVector.bvULEQ xBnds.Upper yBnds.Lower) then 59 | True 60 | elif not (BitVector.bvULEQ xBnds.Lower yBnds.Upper) then 61 | False 62 | else 63 | Undefined 64 | | _ -> assert (false) 65 | Undefined) // Error 66 | 67 | let rhs = getRhsBounds r pBounds pNumerals 68 | let lhs = getLhsBounds r pBounds pNumerals 69 | if rhs.isEmpty || lhs.isEmpty then 70 | False 71 | else 72 | let res = relOp lhs rhs 73 | 74 | // dbg <| (lazy (sprintf " | %s in %s %s %s in %s => %s" 75 | // (if (r.isSimpleRelation) then 76 | // (r.getArgumentString 0) 77 | // elif r.numArguments = 2 then 78 | // (r.getBVOP.ToString()) + " " + 79 | // r.getArgumentString 0 + " " + 80 | // r.getArgumentString 1 81 | // elif r.numArguments = 1 then 82 | // (r.getBVOP.ToString()) + " " + 83 | // r.getArgumentString 0 84 | // else 85 | // assert(false) 86 | // "") 87 | // (lhs.ToString()) 88 | // (if r.getRelationOP = Z3_decl_kind.Z3_OP_EQ then "=" else "<=") 89 | // (if r.isRhsNumeral then ((!pNumerals).getNumeral (- r.getRhs)).ToString() else (r.getRhs.ToString()) + ":bv") 90 | // (rhs.ToString()) 91 | // (res.ToString()))) 92 | 93 | res 94 | 95 | 96 | let tbndsGetAntecedents (s:State) (tRel:Ref) : Literal list = 97 | let lex = (!s.bounds).L_explanation 98 | let uex = (!s.bounds).U_explanation 99 | 100 | // The situation is tRel: (op a0 a1) = rhs 101 | // the antecedents of tRel are the bounds for a0, a1, and rhs, 102 | // i.e., a maximum of 6 different Boolean variables (negated). 103 | 104 | // Note: BV variables occurring in bounds constraints can have 105 | // the same bounds constraint's boolVar as a reason (e.g., when they 106 | // appear on decision level 0). 107 | 108 | let nbv = Negate ((!tRel).getBoolVar) 109 | let mutable t = [] 110 | for i in 0 .. (!tRel).numArguments do 111 | if not ((!tRel).isArgumentNumeral i) then 112 | let ll = Negate lex.[(!tRel).getArgument i] 113 | let ul = Negate uex.[(!tRel).getArgument i] 114 | for lit in [ll; ul] do 115 | if lit <> 0 && lit <> nbv && 116 | not (List.exists (fun x -> x = lit) t) then 117 | t <- lit :: t 118 | t 119 | 120 | 121 | let tbndsGetImplication (s:State) (tRel:Ref) (holds:Val) = 122 | // Whenever this function is called, we know that tbndsHolds is True or False. 123 | assert (holds <> Undefined) 124 | 125 | // CMW: The name of this function is not great, here's a description: 126 | // Suppose there is a conflict between (...) -> boolVar and 127 | // (only bounds) -> -boolVar. We need to make the latter explicit by 128 | // providing a clause that contains all antecedents, and which 129 | // implies -boolVar (swap polarity when holds = False) 130 | 131 | let boolVar = (!tRel).getBoolVar 132 | let ants = (tbndsGetAntecedents s tRel) 133 | let lit = if holds = True then var2lit boolVar else Negate boolVar 134 | let ants_contains_lit = (List.tryFind(fun x -> x = lit) ants).IsSome 135 | assert(not ants_contains_lit) 136 | let cl = newClauseFromList (lit :: ants) 137 | checkExplanation s.trail s.database s.bvVal s.bounds cl false false true 138 | (cl, lit) 139 | 140 | 141 | let tbndsGeneralize (s:State) (expl:Clause) : Clause = 142 | // TODO: Bounds generalization 143 | expl 144 | 145 | 146 | //let tbndsCheckConsistency (s:State) (wRel:Ref) = 147 | // let holds = tbndsHolds (!wRel) s.bounds s.numeralDB 148 | // let valB = (!s.bVal).getValueB (!wRel).getBoolVar 149 | // match (holds,valB) with 150 | // | (True,False) 151 | // | (False,True) -> 152 | // let cnflctCls = tbndsExplainConflict s wRel 153 | // s.conflict <- Some (ref cnflctCls) 154 | // | _ -> () 155 | 156 | 157 | let implyBoundPredicate (s:State) (antecedants:Literal list) (boundPred:Ref) = 158 | assert(not antecedants.IsEmpty) 159 | let lbVar = (!boundPred).getBoolVar 160 | let imp = newClauseFromList (lbVar :: antecedants) 161 | 162 | match (!s.bVal).getValueB lbVar with 163 | | True -> 164 | // AZ: If the predicates are normalized then this should work 165 | // CMW: So, are they normalized? 166 | () 167 | | False -> s.SetConflict (Some (ref imp)) 168 | | Undefined -> 169 | checkExplanation s.trail s.database s.bvVal s.bounds imp false false true 170 | s.Push (Imp (ref imp, lbVar)) 171 | //assert(not s.IsConflicted) AZ: cross theory conflcits can occur 172 | 173 | 174 | let tbndsImplyNewInterval (s:State) (antecedants:Literal list) (bvVar:Var) (newIntvl:Interval) = 175 | 176 | // The situation is newInterval.lower < bvVar < newInterval.upper. 177 | // See tImplyNewValue in RLEBVTheory. 178 | // For the bounds, the difference is that we need to introduce 179 | // "interval-Predicates" instead of MAPredicates. 180 | 181 | let oldIntvl = (!s.bounds).get bvVar 182 | 183 | if not (BitVector.bvEQ oldIntvl.Lower newIntvl.Lower) then 184 | let lbPredicate = getLowerBoundPredicate s.database bvVar newIntvl.Lower s.bVal s.bvVal s.bounds 185 | implyBoundPredicate s antecedants (ref lbPredicate) 186 | 187 | if s.IsSearch then 188 | if not (BitVector.bvEQ oldIntvl.Upper newIntvl.Upper) then 189 | let ubPredicate = getUpperBoundPredicate s.database bvVar newIntvl.Upper s.bVal s.bvVal s.bounds 190 | implyBoundPredicate s antecedants (ref ubPredicate) 191 | 192 | 193 | let tbndsGetImpliedBounds (s:State) (tRel:Ref) (polarity:Val) = 194 | assert ((!s.bVal).getValueB ((!tRel).getBoolVar) <> Undefined) 195 | let boolVar = (!tRel).getBoolVar 196 | let varBoundPairs = tbndsGetNewValues (!tRel) polarity s.bounds s.numeralDB 197 | 198 | let expl = (if polarity = True then Negate boolVar else boolVar) :: (tbndsGetAntecedents s tRel) 199 | 200 | for (bvVar, newBounds) in varBoundPairs do 201 | let oldBounds = (!s.bounds).get bvVar 202 | 203 | if s.IsConflicted || bvVar = 0 || (Interval.Equal newBounds oldBounds) then 204 | () 205 | else if newBounds.isEmpty then 206 | verbose <| (lazy (sprintf " | ==> Domain of %s:bv is empty; %s => False" (bvVar.ToString()) (clauseToString (newClauseFromList expl)))) 207 | let cc = newClauseFromList (expl) 208 | s.SetConflict (Some (ref cc)) 209 | else 210 | // CMW: bvVar is assigned new bounds (newBnds), but that new Interval 211 | // does not necessarily depend on all the literals in `expl`, so 212 | // this can be optimized. (Maybe add explanation finding to evalBounds?) 213 | tbndsImplyNewInterval s expl bvVar newBounds 214 | 215 | 216 | let tbndsEvaluateAtLeast1U (s:State) (tRel:Ref) = 217 | let nums = s.numeralDB 218 | let pVal = s.bVal 219 | let rel = !tRel 220 | let boolVar = rel.getBoolVar 221 | let bVal = (!pVal).getValueB boolVar 222 | 223 | if bVal = Undefined then 224 | let holds = tbndsHolds (!tRel) s.bounds s.numeralDB 225 | if holds <> Undefined then 226 | let (expl, l) = tbndsGetImplication s tRel holds 227 | s.Push (Imp (ref expl, l)) 228 | // assert(not s.IsConflicted || s.isInTempMode) 229 | else 230 | tbndsGetImpliedBounds s tRel bVal 231 | 232 | // CMW: this is an optimization to get conflicts earlier. 233 | // tbndsCheckConsistency s tRel 234 | 235 | 236 | let tbndsEvaluate0U (s:State) (tRel:Ref) = 237 | // The TRel can be fully evaluated and checked against the trail. 238 | // If it agrees with the trail, it's valueT is set 239 | // If it contradicts the trail, a conflict is detected. 240 | // If it is not present on the trail, it is propagated. 241 | let pVal = s.bVal 242 | let boolVar = (!tRel).getBoolVar 243 | 244 | let holds = tbndsHolds (!tRel) s.bounds s.numeralDB 245 | let bval = ((!pVal).getValueB boolVar) 246 | match (holds, bval) with 247 | 248 | | (True, True) -> (!pVal).setValueT boolVar (!s.trail).getNumDecisions |>ignore 249 | | (False, False) -> (!pVal).setValueT (Negate boolVar) (!s.trail).getNumDecisions |>ignore 250 | 251 | | (True, False) 252 | | (False, True) -> 253 | let (expl, l) = tbndsGetImplication s tRel holds 254 | s.SetConflict (Some (ref expl)) 255 | 256 | | (True, Undefined) 257 | | (False, Undefined) -> 258 | let (expl, l) = tbndsGetImplication s tRel holds 259 | s.Push (Imp (ref expl, l)) 260 | 261 | | (Undefined, _) -> 262 | // While this case can't happen in the RLEBV theory, it can be triggered 263 | // in the bounds theory when the bounds are not strong enough. 264 | () 265 | 266 | 267 | let tbndsEvaluate (s:State) (tRel:Ref) = 268 | // match (numUnboundedVariables !tRel s.bounds) with 269 | // | 0 -> 270 | // // Problem: 0 unbounded variables means this is called very 271 | // // often, with small chance of success. 272 | // tbndsEvaluate0U s tRel 273 | // | _ -> 274 | // tbndsEvaluateAtLeast1U s tRel 275 | 276 | // CMW: In each iteration, first run bounds update, 277 | // then check for conflict/implication/etc. "numUnboundedVariables" 278 | // is not a good indicator for whether we will see bounds updates. 279 | tbndsEvaluateAtLeast1U s tRel 280 | tbndsEvaluate0U s tRel -------------------------------------------------------------------------------- /BoundsValuation.fs: -------------------------------------------------------------------------------- 1 | module BoundsValuation 2 | 3 | open Literal 4 | open BitVector 5 | open Util 6 | open Interval 7 | 8 | 9 | type BoundsValuation (size:int, sorts:VarType[]) = 10 | let mutable allocated = size + 1 11 | let mutable reallocCoefficient = 2.0 12 | 13 | member val private inUse = size + 1 with get, set 14 | 15 | member val bounds = [|for s in sorts do 16 | if s > 0 then 17 | yield Interval.Full (s) 18 | else 19 | yield Interval.Empty (1) |] with get, set 20 | 21 | member val L_explanation = Array.create (size + 1) (0:Literal) with get, set 22 | member val U_explanation = Array.create (size + 1) (0:Literal) with get, set 23 | 24 | member val private inTempMode = false with get, set 25 | member val private snapshot = -1 with get, set 26 | 27 | member r.getInUse = r.inUse 28 | member r.reallocate() = 29 | let newSize = int (reallocCoefficient * float allocated) 30 | r.reallocate newSize 31 | 32 | member r.reallocate (newSize:int) = 33 | r.bounds <- Array.append r.bounds (Array.create ((newSize + 1) - allocated) (Interval.Empty 1) ) 34 | r.L_explanation <- Array.append r.L_explanation (Array.create ((newSize + 1) - allocated) 0) 35 | r.U_explanation <- Array.append r.U_explanation (Array.create ((newSize + 1) - allocated) 0) 36 | allocated <- r.bounds.Length 37 | 38 | member r.fastForward (oInUse: int) (sorts: Ref) = 39 | if r.inUse < oInUse then 40 | if oInUse > allocated then 41 | r.reallocate oInUse 42 | for i in r.inUse .. oInUse - 1 do 43 | r.newVar i (!sorts).[i] 44 | assert (r.inUse = oInUse) 45 | 46 | member r.newVar (var:Var) (s:VarType) = 47 | assert(var = r.inUse) 48 | if r.inUse = allocated then 49 | r.reallocate() 50 | r.inUse <- r.inUse + 1 51 | if (s <> 0) then 52 | let bv = BitVector s 53 | r.bounds.[var] <- Interval(bv.Minimum, bv.Maximum) 54 | dbg <| (lazy sprintf " | initial bound: %s <= %d:bv" (r.bounds.[var].ToString()) var) 55 | 56 | member r.set (i:Var) (bounds:Interval) = 57 | assert (sorts.[i] = bounds.Dimension) 58 | r.bounds.[i] <- bounds 59 | 60 | member r.getExplanations v = (r.L_explanation.[v], r.U_explanation.[v]) 61 | 62 | member r.get(i:Var) = 63 | assert (r.bounds.[i].Dimension <> 0) 64 | r.bounds.[i] 65 | 66 | member r.enterTempMode (orig:Ref) (sorts:Ref) = 67 | assert (not r.inTempMode ) 68 | assert (r.snapshot = -1) 69 | r.inTempMode <- true 70 | r.snapshot <- (!orig).getInUse 71 | r.fastForward r.snapshot sorts 72 | 73 | assert (r.inUse = (!orig).getInUse) 74 | assert (Array.fold (fun s (x:int) -> s && x = 0) true r.L_explanation) 75 | assert (Array.fold (fun s (x:int) -> s && x = 0) true r.U_explanation) 76 | for i in 1 .. r.inUse - 1 do 77 | assert ( (!sorts).[i] = 0 && r.bounds.[i].isEmpty || r.bounds.[i].Dimension = (!sorts).[i] && r.bounds.[i].isFull) 78 | assert (r.bounds.[i].Dimension = (!orig).bounds.[i].Dimension) 79 | 80 | 81 | member r.leaveTempMode = 82 | assert(r.inTempMode) 83 | assert(r.snapshot >= 0) 84 | for i in r.snapshot .. r.inUse - 1 do 85 | r.bounds.[i] <- Interval.Empty 1 86 | r.L_explanation.[i] <- 0 87 | r.U_explanation.[i] <- 0 88 | 89 | r.inUse <- r.snapshot 90 | r.snapshot <- -1 91 | r.inTempMode <- false 92 | 93 | // member r.setLower (i:Var) (bv:BitVector)= 94 | // assert (r.isBVVar i) 95 | // assert (r.bounds.[i].Length <> 0) 96 | // 97 | // bv.CheckInvariant() 98 | // dbg <| (lazy sprintf " | new bound: %s <= %d:bv" (bv.ToString()) i) 99 | // r.lower.[i] <- bv 100 | 101 | 102 | 103 | // member r.setUpper (i:Var) (bv:BitVector)= 104 | // assert (r.isBVVar i) 105 | // assert (r.upper.[i].Length <> 0) 106 | 107 | // bv.CheckInvariant() 108 | // dbg <| (lazy sprintf " | new bound: %d:bv <= %s" i (bv.ToString())) 109 | // r.upper.[i] <- bv -------------------------------------------------------------------------------- /Clause.fs: -------------------------------------------------------------------------------- 1 | module Clause 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | open Literal 6 | 7 | //|Size|l_1|...|l_size| 8 | 9 | type Clause = Literal [] 10 | 11 | type ClauseStatus = 12 | | Sat 13 | | Unsat 14 | | Implication 15 | | Unknown 16 | 17 | let emptyClause = [|0;|] 18 | 19 | let getSize(c:Clause) = c.[0] 20 | let isEmptyClause (c:Clause) = getSize c = 0 21 | let getLiterals (c:Clause) = (Array.sub c 1 (getSize c)) 22 | 23 | let normalizeLiteralList (cls:Literal list) = 24 | List.sortWith (fun x y -> lit2var y - lit2var x) cls 25 | 26 | let newClauseFromArray (ls:Literal []) :Clause = 27 | let sz = Array.length ls 28 | Array.append [|sz|] ls 29 | 30 | 31 | let newClauseFromList (ls:Literal list) :Clause = 32 | let sz = List.length ls 33 | List.toArray (sz :: ls) 34 | 35 | 36 | let clauseToString(c:Clause) = 37 | let mutable s = ['(';] 38 | for i in 1 .. getSize(c) do 39 | if i <> 1 then s <- s@[' '] 40 | s <- s@(Array.toList (c.[i].ToString().ToCharArray())) 41 | s <- s@[')'] 42 | let ss = s 43 | new string [|for c in ss -> c|] 44 | 45 | 46 | let expr2Clause lit2id (c:Expr) : Clause = 47 | if c.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_OR then 48 | let lits = Array.map (expr2Lit lit2id) (c.Args) 49 | newClauseFromArray lits 50 | else 51 | newClauseFromList [expr2Lit lit2id c] 52 | 53 | 54 | let clauseContainsDuplicates (c:Clause) = 55 | let mutable has_dupes = false 56 | for i in 1 .. getSize(c) do 57 | for j in i + 1 .. getSize(c) do 58 | if c.[i] = c.[j] then 59 | has_dupes <- true 60 | has_dupes 61 | 62 | 63 | let collectLiterals (ls:Literal list) = 64 | let mutable cls = [] 65 | for l in ls do 66 | if l <> 0 && not (List.exists (fun x -> x = l) cls) then 67 | cls <- l :: cls 68 | cls 69 | 70 | 71 | type ClauseComparer () = 72 | interface IEqualityComparer with 73 | 74 | override r.GetHashCode(c) = 75 | let mutable h = getSize c 76 | for i in 1 .. getSize c do 77 | h <- h ^^^ c.[i] 78 | h 79 | 80 | override r.Equals(c1:Clause, c2:Clause) = 81 | if getSize c1 = getSize c2 then 82 | let s1 = Array.sort c1 83 | let s2 = Array.sort c2 84 | let mutable e = true 85 | for i in 1 .. getSize c1 do 86 | if s1.[i] <> s2.[i] then 87 | e <- false 88 | e 89 | else 90 | false 91 | 92 | -------------------------------------------------------------------------------- /ClauseDB.fs: -------------------------------------------------------------------------------- 1 | module ClauseDB 2 | 3 | open Microsoft.Z3 4 | open System.Collections.Generic 5 | open GlobalOptions 6 | open Util 7 | open Literal 8 | open Clause 9 | open BooleanValuation 10 | 11 | 12 | type ClauseDB private () = 13 | let reallocCoefficient = 0.5 14 | let minSize = 5 15 | 16 | new (g:Goal, expr2var:Dictionary) as this = 17 | ClauseDB() 18 | then 19 | this.init(g, expr2var) 20 | 21 | member val private clauses = [||] with get, set 22 | member val private allocatedSize = 0 with get, set 23 | member val private originalSize = 0 with get, set 24 | member val private storedClauses = new HashSet( new ClauseComparer()); 25 | member val private tseitin = new Dictionary(new ClauseComparer()); 26 | 27 | member val count = 0 with get, set 28 | member val originalClauses = [||] with get, set 29 | member val units = [||] with get, set 30 | 31 | 32 | member r.addUnit (l:Literal) = 33 | r.units <- Array.append r.units [|(newClauseFromArray [|l|])|] 34 | 35 | member r.init (g:Goal, expr2var:Dictionary) = 36 | r.originalClauses <- (Array.map (expr2Clause expr2var) (g.Formulas)) 37 | r.clauses <- Array.filter (fun (x:Clause) -> x.[0] <> 1) r.originalClauses 38 | r.units <- (Array.filter (fun (x:Clause) -> getSize(x) = 1) r.originalClauses) 39 | for c in r.originalClauses do 40 | if not (r.isStored c) then 41 | r.store c 42 | 43 | assert (r.allocatedSize = 0) 44 | let len = Array.length r.clauses 45 | if len > 0 then 46 | r.originalSize <- Array.length r.clauses 47 | r.count <- r.originalSize 48 | r.allocatedSize <- r.originalSize 49 | else 50 | r.clauses <- Array.create minSize [|0|] 51 | r.originalSize <- 0 52 | r.count <- 0 53 | r.allocatedSize <- minSize 54 | 55 | member private r.reallocate () = 56 | assert (r.allocatedSize > 0) //This ensures that init ran before first reallocation 57 | let before = r.allocatedSize 58 | let si = int (reallocCoefficient * (float r.allocatedSize)) 59 | let sizeIncrement = if si <= 0 then 1 else si 60 | r.clauses <- Array.append r.clauses (Array.create sizeIncrement emptyClause) 61 | r.allocatedSize <- r.allocatedSize + sizeIncrement 62 | assert(r.allocatedSize > before) 63 | 64 | member private r.isLegal (ind:int) = 65 | 0 <= ind && ind <= r.count 66 | 67 | member r.getClause(i:int) = //clsDB.[i] 68 | assert (r.isLegal i) 69 | r.clauses.[i] 70 | 71 | member r.getClauseRef(i:int) = //ref clsDB.[i] 72 | assert (r.isLegal i) 73 | ref (r.clauses.[i]) 74 | 75 | member r.isLearned(i:int) = 76 | assert (r.isLegal i) 77 | i >= r.originalSize 78 | 79 | member r.isStored (c:Clause) = r.storedClauses.Contains c 80 | 81 | member r.store (c:Clause) = r.storedClauses.Add c |> ignore 82 | 83 | member r.getTseitinDefinition (c:Clause) = 84 | if r.tseitin.ContainsKey c then 85 | Some (r.tseitin.Item c) 86 | else 87 | None 88 | 89 | member r.registerTseitin (c:Clause) (v:Var) = r.tseitin.Add (c, v) 90 | 91 | member r.isRegisteredTseitin (v:Var) = r.tseitin.ContainsValue v 92 | 93 | 94 | //Intended use: 95 | // we have a new clause to add, either through learning or a generated explanation or w/e 96 | // 1. Add the clause, obtain its pointer in the DB 97 | // 2. Run getWatches over the reference and add the pointers where necessary 98 | member r.addClause (c:Clause) = 99 | assert (getSize c > 1) 100 | assert (not (r.isStored c)) 101 | // dbg <| (lazy sprintf "Adding clause: %s" (clauseToString c)) 102 | if r.count = r.allocatedSize then 103 | r.reallocate () 104 | 105 | let index = r.count 106 | r.clauses.[index] <- c 107 | r.store c 108 | r.count <- r.count + 1 109 | index 110 | 111 | member r.printClause (clause:Ref) = 112 | printf "[" 113 | for j in 1 .. (!clause).[0] do 114 | printf " %d " (!clause).[j] 115 | printf "]" 116 | 117 | member r.eval (bVal:Ref) (clsR:Ref) = 118 | let cls = !clsR 119 | let size = getSize(cls) 120 | let mutable res = false 121 | 122 | if size > 0 then 123 | let cnt = cls 124 | |> Array.map (fun (x:Literal) -> (!bVal).getValueB x) 125 | |> Array.sumBy (fun (x:Val) -> if x = False then 0 else 1) 126 | cnt > 0 127 | else 128 | printf "Zero size clause in the DB!" 129 | false 130 | 131 | member r.Check (bVal:Ref) : bool = 132 | let mutable q = true 133 | for i in 0 .. r.count - 1 do 134 | let cls = r.getClause i 135 | if not (r.eval bVal (ref cls)) then 136 | printf "Conflict:" 137 | r.printClause (ref cls) 138 | q <- false 139 | q 140 | 141 | override r.ToString() = 142 | if r.count = 0 then 143 | "ClauseDB: EMPTY" 144 | else 145 | let mutable res = "ClauseDB: (" + (r.count.ToString()) + " clauses)" + System.Console.Out.NewLine 146 | for i in 0 .. r.count - 1 do 147 | let c = r.getClause i 148 | res <- res + (clauseToString(c)) + System.Console.Out.NewLine 149 | res -------------------------------------------------------------------------------- /ConflictRules.fs: -------------------------------------------------------------------------------- 1 | module ConflictRules 2 | 3 | open GlobalOptions 4 | open Util 5 | open Stats 6 | open Literal 7 | open Clause 8 | open BooleanValuation 9 | open Learning 10 | open Trail 11 | open State 12 | open Z3Check 13 | 14 | 15 | let mutable private rc_seen : bool[] = [||] 16 | 17 | let resolveConflict (s:State) = 18 | dbg <| (lazy sprintf "== Conflict ====================================================================") 19 | assert(s.IsConflicted) 20 | 21 | let trail = !s.trail 22 | let valuation = !s.bVal 23 | let mutable learnedLits = [] 24 | let mutable lit = (0:Literal) 25 | let mutable cnflct = s.GetConflictClause 26 | let mutable pathC = 0 27 | let mutable guard = true 28 | 29 | (!(!s.database).Statistics).Conflict() 30 | 31 | let maxVar = (!s.variableDB).highestVarInUse 32 | if rc_seen.Length <= maxVar then 33 | rc_seen <- Array.append rc_seen (Array.create (maxVar + 1 - rc_seen.Length) false) 34 | 35 | let c = !cnflct 36 | for i in 1 .. getSize(c) do 37 | assert((trail.getLevelExpensive c.[i]) = (valuation.getBLvl c.[i]) || i = 1) 38 | // AZ: This exception is for the Tseitin variable which is not actually occuring on the trail. 39 | 40 | // CMW: Array.fold behaves weirdly sometimes, and I have no idea why. 41 | // let conflict_level = Array.fold (fun mxlvl lit -> max (valuation.getBLvl lit) mxlvl) 0 c 42 | let mutable conflict_level = 0 43 | for i in 1 .. getSize(c) do 44 | conflict_level <- max conflict_level (valuation.getBLvl c.[i]) 45 | 46 | dbg <| (lazy sprintf "Conflict clause: %s" (clauseToString c)) 47 | dbg <| (lazy sprintf "Conflict #: %d" (!(!(!s.database).Statistics).conflicts)) 48 | dbg <| (lazy sprintf "# decisions: %d" trail.getNumDecisions) 49 | let cl = conflict_level 50 | dbg <| (lazy sprintf "Conflict level: %d" cl) 51 | dbg <| (lazy (let mutable str = "Literal levels: " 52 | for i in 1 .. c.Length - 1 do 53 | str <- str + (sprintf "%d - %d (%d)\t" c.[i] (valuation.getBLvl c.[i]) (trail.getLevelExpensive c.[i])) 54 | str)) 55 | 56 | // CMW: Some conflict clauses are created on the fly by the theories and 57 | // they can be incorrect, so we check them here, before anything is 58 | // derived from them. 59 | // trail.forcePrint("", s.bvVal, s.bounds) 60 | // if DBG then 61 | // dbg <| (lazy "Pre-conflict resolution check") 62 | // checkExplanation s.trail s.database s.partAssignment s.bounds c false true true 63 | assert(checkClauseIsFalse s.bVal !cnflct) 64 | 65 | if VRB then 66 | s.printConflict cnflct 67 | 68 | if conflict_level = 0 then 69 | s.MarkUNSAT 70 | else 71 | // // CMW: The following assertion can be violated, because empty domains 72 | // // are detected during decision making. Therefore, for a number of levels, 73 | // // the empty domain can go undetected and thus the decision level will be 74 | // // larger than the conflict level. 75 | // let mutable max_lvl = -1 76 | // for i in 1 .. (getSize c) do 77 | // max_lvl <- (max (trail.getLevel c.[i]) max_lvl) 78 | // assert(((getSize c) = 1 && max_lvl = 0) || 79 | // max_lvl = (trail.getNumDecisions)) 80 | 81 | while guard do 82 | assert (conflict_level > 0) 83 | let c = !cnflct 84 | let pc = pathC 85 | 86 | let start = if lit=0 then 1 else 2 87 | 88 | // CMW: This conflict resolution algorithm relies 89 | // on the fact that the implied literal is the 90 | // first literal in `cnflct'. 91 | if (lit <> 0 && (!cnflct).[1] <> lit) then 92 | printfn("Bug: Clause sorted incorrectly.") ; 93 | assert(false) 94 | 95 | for i in start .. getSize !cnflct do 96 | let lit = (!cnflct).[i] 97 | let lvl = valuation.getBLvl lit 98 | if not rc_seen.[lit2var lit] && lvl > 0 then 99 | rc_seen.[lit2var ((!cnflct).[i])] <- true 100 | if lvl >= conflict_level then 101 | pathC <- pathC + 1 102 | else 103 | learnedLits <- lit :: learnedLits 104 | 105 | if DBG then 106 | if (lit = 0) then 107 | printfn "---------------------------------------------------" 108 | else 109 | let v = (lit2var lit) 110 | printf " | /\ (" 111 | let mutable first = true 112 | for i in 1 .. (getSize c) do 113 | let cl = c.[i] 114 | if (cl <> lit) then 115 | if first then 116 | first <- false 117 | else 118 | printf " && " 119 | printf "%d" (Negate cl) 120 | printf ") => " 121 | // printf " (pathC=%d)" pc 122 | if (!s.theoryDB).isDefined v then 123 | if (lit < 0) then printf "not " 124 | printf "%s" (((!s.theoryDB).getThRelation v).ToString(s.numeralDB)) 125 | else 126 | printf "%d" lit 127 | printfn "" 128 | 129 | let mutable indx = trail.getCount - 1 130 | while indx > 0 && not rc_seen.[lit2var (trail.getLiteral indx)] do //|| trail.getNumDecisions >= conflict_level) 131 | s.Pop 132 | indx <- indx - 1 133 | 134 | lit <- trail.getLiteral indx 135 | cnflct <- trail.getExplanation indx 136 | rc_seen.[lit2var lit] <- false 137 | pathC <- pathC - 1 138 | s.Pop 139 | 140 | if pathC <= 0 then 141 | guard <- false 142 | 143 | assert(lit<>0); 144 | let bt_lvl = List.fold (fun a x -> let l = (valuation.getBLvl x) 145 | if l > a then l else a) 0 learnedLits 146 | 147 | assert((valuation.getBLvl (lit2var lit)) = -1) 148 | assert(bt_lvl < conflict_level) 149 | 150 | learnedLits <- (Negate lit) :: learnedLits 151 | let learnedClause = newClauseFromList learnedLits 152 | 153 | while trail.getNumDecisions > bt_lvl do 154 | s.Pop 155 | 156 | assert(valuation.getValueB(lit) = Undefined) 157 | 158 | for i in 1 .. getSize learnedClause do 159 | rc_seen.[lit2var learnedClause.[i]] <- false 160 | if DBG then 161 | printfn "---------------------------------------------------" 162 | printf " | -> (" 163 | let mutable first = true 164 | let alit = (Negate lit) 165 | for i in 1 .. getSize learnedClause do 166 | let cl = learnedClause.[i] 167 | if cl <> alit then 168 | if first then 169 | first <- false 170 | else 171 | printf " && " 172 | printf "%d" (Negate cl) 173 | printf ") => " 174 | if (!s.theoryDB).isDefined (lit2var alit) then 175 | if (alit < 0) then printf "not " 176 | printf "%s " (((!s.theoryDB).getThRelation (lit2var alit)).ToString(s.numeralDB)) 177 | else 178 | printf "%d " alit 179 | printfn "" 180 | printfn "---------------------------------------------------" 181 | dbg <| (lazy sprintf "Decision level now: %d" trail.getNumDecisions) 182 | 183 | s.ClearConflict 184 | 185 | if (getSize learnedClause) > 1 then 186 | checkExplanation s.trail s.database s.bvVal s.bounds learnedClause false false true 187 | //AZ: There are cases when we can produce a known clause, because it 188 | // can be propagated only in a certain order. 189 | // E.g., x =/= a when x in [l,...,a,..., u] Nothing happens 190 | // x <= a when x in [l,...,a,..., u] yields [l,... a] 191 | // x >= a when x in [l,...,a] yields [a,a] which conflicts 192 | if not ((!s.clauseDB).isStored learnedClause) then 193 | s.Learn learnedClause |> ignore 194 | 195 | s.Push (Imp (ref learnedClause, Negate lit)) // Note: this may set a new (theory-dependant) conflict 196 | 197 | dbg <| (lazy sprintf "== Resolved ====================================================================") 198 | () 199 | -------------------------------------------------------------------------------- /DataBase.fs: -------------------------------------------------------------------------------- 1 | module Database 2 | 3 | open System 4 | open System.Collections.Generic 5 | 6 | open Microsoft.Z3 7 | 8 | open Util 9 | open Stats 10 | open Literal 11 | open Clause 12 | open BitVector 13 | open TheoryRelation 14 | open NumeralDB 15 | open VariableDB 16 | open ClauseDB 17 | open TheoryDB 18 | open WatchManager 19 | 20 | open BooleanValuation 21 | open BitVectorValuation 22 | open BoundsValuation 23 | 24 | type Database = class 25 | val Numerals : Ref 26 | val Variables : Ref 27 | val Clauses : Ref 28 | val Theory : Ref 29 | val Watches : Ref 30 | 31 | val Statistics : Ref 32 | 33 | val var2sort : int[] 34 | val expr2var : Dictionary 35 | val num2id : Dictionary 36 | 37 | val mutable private inTempMode : bool 38 | 39 | new (maxVariable, num2id, var2sort, expr2var, goal) = 40 | let n = ref (new NumeralDB(num2id)) 41 | let v = ref (new VariableDB(var2sort)) 42 | let c = ref (new ClauseDB(goal, expr2var)) 43 | let t = ref (new TheoryDB(expr2var, num2id, n, c)) 44 | let w = ref (new WatchManager(maxVariable, 10, t)) 45 | let s = ref (new Statistics()) 46 | { 47 | Statistics = s; 48 | Numerals = n; 49 | Variables = v; 50 | Clauses = c; 51 | Theory = t; 52 | Watches = w; 53 | var2sort = var2sort; 54 | expr2var = expr2var; 55 | num2id = num2id; 56 | inTempMode = false; 57 | } 58 | new (numDB, varDB, thDB, wMngr, goal) = 59 | let n = numDB 60 | let v = varDB 61 | let c = ref (new ClauseDB(goal, new Dictionary())) 62 | let t = thDB 63 | let w = wMngr//ref (new WatchManager(maxVariable, 10, t)) 64 | let s = ref (new Statistics()) 65 | { 66 | Statistics = s; 67 | Numerals = n; 68 | Variables = v; 69 | Clauses = c; 70 | Theory = t; 71 | Watches = w; 72 | var2sort = null; 73 | expr2var = null; 74 | num2id = null 75 | inTempMode = false; 76 | } 77 | 78 | member this.enterTempMode (orig:Ref) = 79 | assert(not this.inTempMode) 80 | assert (this.Variables = (!orig).Variables) 81 | assert (this.Numerals = (!orig).Numerals) 82 | assert (this.Theory = (!orig).Theory) 83 | this.inTempMode <- true 84 | (!this.Variables).enterTempMode() 85 | (!this.Numerals).enterTempMode() 86 | (!this.Theory).enterTempMode() 87 | //(!this.Watches).enterTempMode((!this.Variables).highestVarInUse) 88 | 89 | member this.leaveTempMode() = 90 | assert(this.inTempMode) 91 | (!this.Variables).leaveTempMode 92 | (!this.Theory).leaveTempMode 93 | (!this.Numerals).leaveTempMode 94 | //(!this.Watches).leaveTempMode 95 | this.inTempMode <- false 96 | 97 | 98 | member this.mkFreshBooleanVariable () = 99 | let res = (!this.Variables).newBooleanVariable () 100 | (!this.Watches).newVarToWatch res 101 | res 102 | 103 | member this.mkFreshBitVectorVariable (size:int) = 104 | let res = (!this.Variables).newBitVectorVariable size 105 | (!this.Watches).newVarToWatch res 106 | res 107 | 108 | member this.mkNumeral (value:BitVector) = 109 | (!this.Numerals).newNumeral this.Statistics value 110 | 111 | 112 | member this.addTheoryRelation (t:TheoryRelation) = 113 | let tDB = (!this.Theory) 114 | assert(not (tDB.isIntroduced t)) 115 | let index = tDB.add t 116 | (!this.Statistics).NewThLiteral() 117 | 118 | for v in t.variableArguments do 119 | (!this.Watches).watchBV v index 120 | verbose <| (lazy (sprintf "X New theory relation: %s" (t.ToString(this.Numerals)))) 121 | () 122 | 123 | member this.addToOccurenceLists (t:TheoryRelation) = 124 | assert(this.inTempMode) 125 | let tDB = (!this.Theory) 126 | assert(tDB.isIntroduced t) 127 | 128 | let index = tDB.bool2ThRel.[t.getBoolVar] 129 | 130 | for v in t.variableArguments do 131 | (!this.Watches).watchBVInTmpMode v index 132 | verbose <| (lazy (sprintf "X Fresh watches on theory relation: %s" (t.ToString(this.Numerals)))) 133 | () 134 | 135 | member this.addAndWatchClause (bVal:Ref)(c:Clause) = 136 | 137 | let ind = (!this.Clauses).addClause c 138 | 139 | match findWatch -c.[1] c bVal with 140 | | (_, Clause.Unknown) -> (!this.Watches).watchBool c.[1] ind |>ignore 141 | (!this.Watches).watchBool c.[2] ind |>ignore 142 | Clause.Unknown 143 | | _ -> match findWatch -c.[1] c bVal with 144 | | (_, Clause.Unsat) -> 145 | //this.conflict <- Some (ref c) 146 | assert(false) 147 | Clause.Unsat 148 | | (_, Implication) -> 149 | (!this.Watches).watchBool c.[1] ind |>ignore 150 | (!this.Watches).watchBool c.[2] ind |>ignore 151 | Clause.Implication 152 | | _ -> 153 | (!this.Watches).watchBool c.[1] ind |>ignore 154 | (!this.Watches).watchBool c.[2] ind |>ignore 155 | Clause.Unknown //AZ: is this correct? 156 | 157 | end -------------------------------------------------------------------------------- /DecisionRules.fs: -------------------------------------------------------------------------------- 1 | module DecisionRules 2 | 3 | open System.Numerics 4 | open GlobalOptions 5 | open Util 6 | open Literal 7 | open Clause 8 | open BooleanValuation 9 | open Trail 10 | open State 11 | open BitVector 12 | open Learning 13 | open Explain 14 | open Interval 15 | open Bit 16 | 17 | 18 | let bDecide (s:State) (l:Literal) = 19 | verbose <| (lazy sprintf "Decide %d" l) 20 | assert(not s.IsConflicted) 21 | assert ((!s.bVal).getValueB l = Undefined) 22 | s.Push (BoolDecision l) 23 | assert((!s.theoryDB).isDefined (lit2var l) || not s.IsConflicted) 24 | 25 | 26 | let implyDecision (s:State) (bvVar:Var) (newValue:BitVector) = 27 | let oldValue = (!s.bvVal).getValue bvVar 28 | let newRel = getModelAssignmentPredicate s.database bvVar newValue s.bVal s.bvVal s.bounds 29 | let b = newRel.getBoolVar 30 | let is_more_concrete = newValue.isMoreConcreteThan oldValue 31 | 32 | match (!s.bVal).getValueB (b) with 33 | | True -> true 34 | 35 | | Undefined when is_more_concrete -> 36 | s.Push (BoolDecision b) 37 | true 38 | 39 | | Undefined -> // when not is_more_concrete 40 | UNREACHABLE("Decisions must be more concrete.") 41 | false 42 | 43 | | False -> 44 | false 45 | 46 | 47 | let refineBitPattern (bnds_value:Interval) (pattern:BitVector) finished step (bit:Bit) = 48 | 49 | let mutable to_decide = None 50 | let mutable q = None 51 | 52 | assert(step <> 0) 53 | let refined_pattern = BitVector.changeBits true bit pattern (finished + step - 1) step 54 | assert(not (finished + step = pattern.Length) || refined_pattern.isConcreteValue) 55 | 56 | if refined_pattern.isConcreteValue then 57 | if bnds_value.Contains refined_pattern then 58 | to_decide <- Some (refined_pattern) 59 | else 60 | if step > 1 then 61 | q <- Some (pattern, finished, step/2) 62 | else // Step is too small 63 | () 64 | else 65 | let ref_pat_int = bnds_value.Intersection (Interval (refined_pattern.Minimum, refined_pattern.Maximum)) 66 | 67 | if ref_pat_int.isSingleton then 68 | to_decide <- Some (ref_pat_int.Lower) 69 | elif ref_pat_int.isEmpty then 70 | // Current refinment of the pattern does not fit the bounds, 71 | // attempt to reduce the refinement step or give up on this branch. 72 | if step > 1 then 73 | q <- Some (pattern, finished, step/2) 74 | else // Step is too small 75 | () 76 | else 77 | // advance the search on the current branch 78 | let newFinished = finished + step 79 | let newStep = refined_pattern.Length - newFinished 80 | q <- Some (refined_pattern, newFinished, newStep) 81 | assert (newStep <> 0) 82 | assert (newStep + newFinished <= refined_pattern.Length) 83 | 84 | assert (not (to_decide.IsSome && q.IsSome)) 85 | (to_decide, q) 86 | 87 | let bitpatternDecide (s:State) (bvVar:Var) (rle_value:BitVector) (bnds_value:Interval) = 88 | let mutable decided = false 89 | let mutable num_attmpts = 0 90 | 91 | let prefix = BitVector.getCommonPrefix bnds_value.Lower bnds_value.Upper 92 | let mutable set = BitVector.Intersect rle_value prefix 93 | 94 | if set.isInvalid then // Conflict involves only pattern and the bounds AZ: This check should be done elsewhere? 95 | let maex = ((!s.bvVal).getExplanation bvVar) 96 | let (lex, uex) = ((!s.bounds).getExplanations bvVar) 97 | assert(maex <> lex && maex <> lex) // AZ: This conflict should be caught elsewhere 98 | let cnflct = newClauseFromList(if lex = uex then 99 | [Negate maex; Negate lex] 100 | else 101 | [Negate maex; Negate uex; Negate lex]) 102 | s.SetConflict (Some (ref cnflct)) 103 | else 104 | let dimension = set.estimateSearchSpace() 105 | 106 | if dimension = 0 then 107 | assert(set.isConcreteValue) 108 | decided <- implyDecision s bvVar set 109 | else 110 | let gray_code (n:BitVector) = 111 | BitVector.bvXOR n (BitVector.bvLShiftRight n (BitVector.One n.Length)) 112 | 113 | let mutable cnt = BitVector.AllZero dimension 114 | let mutable overflown = false 115 | 116 | while not decided && not overflown do 117 | let candidate = BitVector.meld set (gray_code cnt) 118 | if bnds_value.Contains candidate then 119 | num_attmpts <- num_attmpts + 1 120 | if (implyDecision s bvVar candidate) then 121 | let na = num_attmpts 122 | dbg <| (lazy sprintf " | (Decided on %d:bv with T:%s and TBnds:%s after %d attempts.)" bvVar (rle_value.ToString()) (bnds_value.ToString()) na) 123 | decided <- true 124 | 125 | cnt <- BitVector.bvAdd cnt (BitVector.One dimension) 126 | overflown <- BitVector.isAllZero cnt 127 | 128 | if not decided then 129 | // CMW: Empty domains are detected during decision making, 130 | // if, for some time, an empty-domain variable is not chosen, 131 | // we will detect the conflict much later. We should try 132 | // to find a cheaper/quicker way of determining empty domains. 133 | // AZ: Empty domain is a conflict and will be detected during 134 | // regular search if it is possible to determine that. 135 | // This is only in the case where the domain is empty but it 136 | // is not trivial to notice it. 137 | verbose <| (lazy sprintf "> The domain of %d:bv is empty." bvVar) 138 | let cflct = explainEmptyDomain s bvVar // TODO: We can collect all the reasons for conflict while trying to make a decision. 139 | s.SetConflict (Some (ref cflct)) 140 | 141 | 142 | let arithmeticDecide (s:State) (bvVar:Var) (rle_value:BitVector) (bnds_value:Interval) = 143 | assert (bvVar <> 0) 144 | assert (rle_value.Length > 0) 145 | let sort = rle_value.Length 146 | 147 | let two = BigInteger 2 148 | 149 | let intersection = bnds_value.Intersection (Interval (rle_value.Minimum, rle_value.Maximum)) 150 | 151 | if intersection.isEmpty then // Conflict involves only bounds and the pattern. AZ: This check should be done elsewhere? 152 | let maex = ((!s.bvVal).getExplanation bvVar) 153 | let (lex,uex) = ((!s.bounds).getExplanations bvVar) 154 | assert(maex <> lex && maex <> lex) // AZ: This conflict should be caught elsewhere 155 | let cnflct = newClauseFromList( if lex = uex then [Negate maex; Negate lex] else [Negate maex; Negate uex; Negate lex]) 156 | s.SetConflict (Some (ref cnflct)) 157 | else 158 | let (lVal, uVal) = (intersection.Lower, intersection.Upper) 159 | 160 | let mutable decided = false 161 | let mutable num_attmpts = 0 162 | 163 | let mutable q = [(lVal, uVal)] 164 | 165 | while q <> [] do 166 | let (lb, ub) = q.Head 167 | q <- q.Tail 168 | let cur = BitVector.bvExtract (sort-1) 0 169 | (BitVector.bvAShiftRight (BitVector.bvAdd 170 | (BitVector.bvZeroExtend lb 1) 171 | (BitVector.bvZeroExtend ub 1)) 172 | (BitVector.One sort)) 173 | assert(BitVector.bvULEQ lb cur) 174 | assert(BitVector.bvULEQ cur ub) 175 | num_attmpts <- num_attmpts + 1 176 | if (rle_value.Contains cur) && 177 | (bnds_value.Contains cur) && 178 | (implyDecision s bvVar cur) then 179 | let na = num_attmpts 180 | dbg <| (lazy sprintf " | (Decided on %d:bv with T:%s and TBnds:%s after %d attempts.)" bvVar (rle_value.ToString()) (bnds_value.ToString()) na) 181 | decided <- true 182 | q <- [] 183 | else 184 | let newUpperBound = BitVector.bvSub cur (BitVector.One sort) 185 | let newLowerBound = BitVector.bvAdd cur (BitVector.One sort) 186 | 187 | if BitVector.bvULEQ lb newUpperBound then 188 | q <- [(lb, newUpperBound)] @ q 189 | 190 | if BitVector.bvULEQ newLowerBound ub then 191 | q <- [(newLowerBound, ub)] @ q 192 | 193 | if not decided then 194 | // CMW: Empty domains are detected during decision making, 195 | // if, for some time, an empty-domain variable is not chosen, 196 | // we will detect the conflict much later. We should try 197 | // to find a cheaper/quicker way of determining empty domains. 198 | // AZ: Empty domain is a conflict and will be detected during 199 | // regular search if it is possible to determine that. 200 | // This is only in the case where the domain is empty but it 201 | // is not trivial to notice it. 202 | verbose <| (lazy sprintf "> The domain of %d:bv is empty." bvVar) 203 | let cflct = explainEmptyDomain s bvVar // TODO: We can collect all the reasons for conflict while trying to make a decision. 204 | s.SetConflict (Some (ref cflct)) 205 | 206 | 207 | // CMW: This is the general tDecide that may use all theories. 208 | let tDecide (s:State) (bvVar:Var) = 209 | assert (bvVar <> 0) 210 | 211 | let rle_value = (!s.bvVal).getValue bvVar // <-- uses partial assignments (pPAs) 212 | let bnds_value = (!s.bounds).get bvVar // <-- also uses bounds 213 | let bp_space_size = rle_value.estimateSearchSpace() 214 | let interval_space_size = bnds_value.estimateSearchSpace() 215 | 216 | if USE_BOUNDS && interval_space_size < bp_space_size then 217 | arithmeticDecide s bvVar rle_value bnds_value 218 | else 219 | bitpatternDecide s bvVar rle_value bnds_value 220 | 221 | 222 | 223 | let chooseVariable (s:State) : Var = 224 | let mutable chosen = false 225 | let mutable v = 0 226 | 227 | while not chosen do 228 | v <- (!s.variableDB).varOrder.next() 229 | if (!s.variableDB).getBitVectorLength v > 0 then 230 | if not ((!s.bvVal).getValue v).isConcreteValue then 231 | chosen <-true 232 | else 233 | if (!s.bVal).getValueB v = Undefined then 234 | chosen <- true 235 | v 236 | 237 | 238 | let decide (s:State) = 239 | assert (not s.variableDB.Value.varOrder.IsEmpty) 240 | let pSorts = (ref (!s.variableDB).sorts) 241 | let mutable decided = false 242 | let mutable v = chooseVariable s 243 | let mutable is_bv = (!pSorts).[lit2var v] > 0 244 | 245 | while not decided do 246 | 247 | if is_bv then 248 | assert (not ((!s.bvVal).getValue v).isConcreteValue) 249 | verbose <| (lazy sprintf "> Making a Model assignment.") 250 | decided <- true 251 | tDecide s v 252 | 253 | if not is_bv then 254 | assert (((!s.bVal).getValueB v) = Undefined) 255 | verbose <| (lazy sprintf "> Making a Boolean decision.") 256 | decided <- true 257 | bDecide s v 258 | 259 | if not decided then 260 | v <- chooseVariable s 261 | is_bv <- (!pSorts).[lit2var v] > 0 262 | -------------------------------------------------------------------------------- /GlobalOptions.fs: -------------------------------------------------------------------------------- 1 | module GlobalOptions 2 | 3 | 4 | // Global flags like debug and possibly other options we might want to add over time 5 | let mutable TRC = false 6 | let mutable DBG = false 7 | let mutable VRB = false //Verbose 8 | let mutable PREPROCESS = true 9 | let mutable SHOWMODEL = false 10 | let mutable RUNZ3CHECKS = false // Default: disabled 11 | let mutable VERIFYMODEL = false // Default: enabled 12 | let mutable POLITE = false //Default: disabled 13 | let mutable GENERALIZE = true 14 | let mutable SHOW_CONFLICTS = false 15 | 16 | let mutable BV_SEGMENT_STRING_LIMIT = 4; 17 | 18 | let mutable USE_BOUNDS = true 19 | 20 | #if INTERACTIVE 21 | let mutable INTERACTIVE = true 22 | #else 23 | let mutable INTERACTIVE = false 24 | #endif 25 | -------------------------------------------------------------------------------- /InitializationRules.fs: -------------------------------------------------------------------------------- 1 | module InitializationRules 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | open GlobalOptions 6 | open Util 7 | open Literal 8 | open BooleanValuation 9 | open Clause 10 | open Trail 11 | open State 12 | open WatchManager 13 | open VariableDB 14 | open ClauseDB 15 | open TheoryDB 16 | open TheoryRelation 17 | open BitVector 18 | open BitVectorValuation 19 | 20 | open RLEBVTheory 21 | open BoundsTheory 22 | 23 | let watchNewClause (s:State) (i:int) = 24 | let trail = !s.trail 25 | let bval = !s.bVal 26 | let cDB = !s.clauseDB 27 | let w = !s.watchManager 28 | let pCls = (!s.clauseDB).getClauseRef i 29 | 30 | assert(getSize(!pCls) > 1) 31 | let (l, r) = findTwoWatches !pCls (s.bVal) 32 | w.watchBool (!pCls).[1] i 33 | w.watchBool (!pCls).[2] i 34 | match r with 35 | | Clause.Unsat -> s.SetConflict (Some pCls) 36 | | Implication -> s.Push (Imp (pCls, (!pCls).[1])) 37 | | _ -> () 38 | 39 | 40 | let pushUnit (s:State) (pCls:Ref) = 41 | assert(getSize(!pCls) = 1) 42 | match (!s.bVal).getValueB((!pCls).[1]) with 43 | | False -> s.SetConflict (Some pCls) 44 | | Undefined -> s.Push (Imp (pCls, (!pCls).[1])) |> ignore 45 | | True -> () // Already True, and therefore on the trail. 46 | 47 | 48 | let pushUnits (s:State) = 49 | dbg <| (lazy "Pushing units: ") 50 | 51 | for c in (!s.clauseDB).units do 52 | let l = c.[1] 53 | let v = lit2var l 54 | 55 | // CMW: We should not need to do anything with model assignments 56 | // or bounds predicates here. This will all be done automatically 57 | // via pushUnit -> ... -> Trail.push 58 | 59 | pushUnit s (ref c) 60 | 61 | let mutable i = 0 62 | while s.IsSearch && i < (!s.clauseDB).count do 63 | watchNewClause s i 64 | i <- i + 1 65 | 66 | 67 | let showWatches (s:State) (l:Literal) = 68 | printfn "(%s): " (l.ToString()) 69 | let lwl = ((!s.watchManager).getWatchList l) 70 | for w in lwl do 71 | printfn "| %s" (clauseToString ((!s.clauseDB).getClause w)) -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | mcBV 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | this software and associated documentation files (the ""Software""), to deal in 11 | the Software without restriction, including without limitation the rights to 12 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 13 | of the Software, and to permit persons to whom the Software is furnished to do 14 | so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /Learning.fs: -------------------------------------------------------------------------------- 1 | module Learning 2 | 3 | open Microsoft.Z3 4 | open Literal 5 | open Numeral 6 | open BitVector 7 | open BooleanValuation 8 | open BitVectorValuation 9 | open BoundsValuation 10 | open TheoryRelation 11 | open Database 12 | 13 | 14 | let private EnsureVariableNumber (bVal:Ref) (bvVal:Ref) (bounds:Ref) (v:Var) (size:int) = 15 | (!bVal).newVar v 16 | (!bvVal).newVar v size 17 | (!bounds).newVar v size 18 | 19 | 20 | let getTseitinVar (db:Ref) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 21 | let newBool = (!db).mkFreshBooleanVariable() 22 | EnsureVariableNumber bVal bvVal bounds newBool 0 23 | newBool 24 | 25 | let getModelAssignmentPredicate (db:Ref) (bvVar:Var) (value:BitVector) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 26 | assert (bvVar > 0) 27 | let newNum = (!db).mkNumeral value 28 | let thRel = TheoryRelation(newNum, Z3_decl_kind.Z3_OP_EQ, bvVar) 29 | match (!(!db).Theory).getThRelationVar thRel with 30 | | (true, boolVar) -> (!(!db).Theory).getThRelation boolVar 31 | | (false, _) -> 32 | let newBool = (!db).mkFreshBooleanVariable () 33 | thRel.setBoolvar newBool 34 | (!db).addTheoryRelation thRel 35 | EnsureVariableNumber bVal bvVal bounds newBool 0 36 | thRel 37 | 38 | 39 | let getBoundPredicate (db:Ref) (bvVar:Var) (value:BitVector) (isLower:bool) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 40 | assert (value.isConcreteValue) 41 | let newNum = (!db).mkNumeral value 42 | let thRel = if isLower then 43 | TheoryRelation(newNum, Z3_decl_kind.Z3_OP_ULEQ, bvVar) 44 | else 45 | TheoryRelation(bvVar, Z3_decl_kind.Z3_OP_ULEQ, newNum) 46 | match (!(!db).Theory).getThRelationVar thRel with 47 | | (true, bVar) -> (!(!db).Theory).getThRelation bVar 48 | | (false, _) -> 49 | let newBool = (!db).mkFreshBooleanVariable () 50 | thRel.setBoolvar newBool 51 | (!db).addTheoryRelation thRel 52 | EnsureVariableNumber bVal bvVal bounds newBool 0 53 | thRel 54 | 55 | let mkRelaxedTRel (db:Ref) (t:TheoryRelation) (value : BitVector) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 56 | assert (t.isSimpleRelation) 57 | 58 | let lhs = t.getArgument 0 59 | let rhs = t.getArgument 1 60 | 61 | assert (isVar lhs || isVar rhs) 62 | assert (not (isVar lhs) || not (isVar rhs)) 63 | 64 | let num = (!db).mkNumeral value 65 | 66 | let newTRel = if isVar lhs then TheoryRelation (lhs, t.getRelationOP, num) 67 | else TheoryRelation (num, t.getRelationOP, rhs) 68 | 69 | match (!(!db).Theory).getThRelationVar newTRel with 70 | | (true, bVar) -> (!(!db).Theory).getThRelation bVar 71 | | (false, _) -> 72 | let newBool = (!db).mkFreshBooleanVariable () 73 | newTRel.setBoolvar newBool 74 | (!db).addTheoryRelation newTRel 75 | EnsureVariableNumber bVal bvVal bounds newBool 0 76 | newTRel 77 | 78 | let getLowerBoundPredicate (db:Ref) (bvVar:Var) (value:BitVector) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 79 | getBoundPredicate db bvVar value true bVal bvVal bounds 80 | 81 | let getUpperBoundPredicate (db:Ref) (bvVar:Var) (value:BitVector) (bVal:Ref) (bvVal:Ref) (bounds:Ref) = 82 | getBoundPredicate db bvVar value false bVal bvVal bounds 83 | -------------------------------------------------------------------------------- /Literal.fs: -------------------------------------------------------------------------------- 1 | module Literal 2 | 3 | open Microsoft.Z3 4 | open System.Collections.Generic 5 | open Util 6 | 7 | type VarType = int 8 | // 0 - Boolean 9 | // Otherwise, denotes BitVector length 10 | 11 | //Variable are numbers from 1 .. maxVar 12 | type Var = int 13 | 14 | let isVar (v:int) = v > 0 15 | 16 | //Literals are +- Vars 17 | type Literal = int 18 | 19 | let var2lit (v:Var) = (v:Literal) 20 | let lit2var (l:Literal) = (abs(l):Var) 21 | 22 | let Negate (l:Literal) = - l 23 | let isNegated (l:Literal) = l < 0 24 | let isPositive (l:Literal) = l > 0 25 | 26 | let mapVariables (g:Goal) (sorts:Dictionary) (expr2Var:Dictionary) = 27 | verbose <| (lazy "Mapping variables...") 28 | let varList = collectConstants g sorts 29 | let len = List.length varList 30 | let var2Expr = Array.create (len+1) null 31 | for p in (List.zip ([1 .. len ]) varList) do 32 | expr2Var.Add( snd p, fst p) 33 | var2Expr.[fst p] <- snd p 34 | verbose <| (lazy " done.") 35 | var2Expr 36 | 37 | let literalMapping (g:Goal) (maxLiteral:Literal)(lit2id:Dictionary) (id2lit:Dictionary) = 38 | verbose <| (lazy "Mapping literals...") 39 | let mutable lits = [] 40 | for cls in g.Formulas do 41 | lits <- lits @ (collectLiterals cls) 42 | let posLits = Set.ofList (List.map removeNegation lits) |> Set.toList 43 | //let sortedLits = List.sortBy (fun (x:Expr) -> x.FuncDecl.Name.ToString()) posLits 44 | let nLen = (maxLiteral+ (List.length posLits)) 45 | for e in (List.zip ([(maxLiteral + 1) .. nLen]) posLits) do 46 | lit2id.Add(snd e, fst e) 47 | id2lit.Add(fst e, snd e) 48 | verbose <| (lazy " done.") 49 | nLen 50 | 51 | 52 | let rec expr2Lit (dic:Dictionary) (e:Expr) = 53 | let mutable l = 0 54 | if e.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_NOT then 55 | l <- (- (expr2Lit dic e.Args.[0])) 56 | else 57 | if not (dic.TryGetValue(e,&l)) then 58 | printfn "Cannot find literal %s" (e.ToString()) 59 | assert(false) 60 | l -------------------------------------------------------------------------------- /Main.fs: -------------------------------------------------------------------------------- 1 | module Main 2 | 3 | open System.Collections.Generic 4 | 5 | open GlobalOptions 6 | open Util 7 | open Solver 8 | open ModelVerification 9 | open State 10 | 11 | let showHelp () = 12 | printfn "mcBV 1.0 (C) Copyright 2016 Microsoft Corporation" 13 | printfn "Usage: mcbv.exe [options] " 14 | printfn "Options:" 15 | printfn "Capital letter sets the option ON, lower letter sets the option OFF [default]" 16 | printfn " -I/i Interactive mode (after solving waits for a key to be pressed) [on]" 17 | printfn " -D/d Debug mode [off]" 18 | printfn " -V/v Verbose mode [off]" 19 | printfn " -T/t Print traces [off]" 20 | printfn " -M/m Print model [off]" 21 | printfn " -Q/q Verify model [on]" 22 | printfn " -C/c Run z3 checks [off]" 23 | printfn " -J/j Just answer [off]" 24 | 25 | 26 | 27 | let parseArguments (argv:array) = 28 | 29 | for arg in argv do 30 | if arg.Chars 0 = '-' then 31 | for c in arg.ToCharArray() do 32 | match c with 33 | | 'I' -> INTERACTIVE <- true 34 | | 'i' -> INTERACTIVE <- false 35 | | 'V' -> VRB <- true 36 | | 'v' -> VRB <- false 37 | | 'D' -> DBG <- true 38 | | 'd' -> DBG <- false 39 | | 'T' -> TRC <- true 40 | | 't' -> TRC <- false 41 | | 'M' -> SHOWMODEL <- true 42 | | 'm' -> SHOWMODEL <- false 43 | | 'Q' -> VERIFYMODEL <- true 44 | | 'q' -> VERIFYMODEL <- false 45 | | 'C' -> RUNZ3CHECKS <- true 46 | | 'c' -> RUNZ3CHECKS <- false 47 | | 'J' -> POLITE <- true 48 | | 'j' -> POLITE <- false 49 | | 'N' -> PREPROCESS <- true 50 | | 'n' -> PREPROCESS <- false 51 | | 'G' -> GENERALIZE <- true 52 | | 'g' -> GENERALIZE <- false 53 | | 'B' -> USE_BOUNDS <- true 54 | | 'b' -> USE_BOUNDS <- false 55 | | 'K' -> SHOW_CONFLICTS <- true 56 | | _ -> () 57 | 58 | Array.filter (fun (x:string) -> x.Chars 0 <> '-' ) argv 59 | 60 | [] 61 | let main argv = 62 | if argv.Length <= 0 then 63 | 64 | showHelp() ; 65 | 30 // `Error' 66 | 67 | else 68 | let before = System.DateTime.Now 69 | let mutable exitStatus = 30 // = Error 70 | 71 | try 72 | let inputs = parseArguments argv 73 | 74 | if inputs.Length <= 0 then 75 | showHelp() 76 | exitStatus <- 30 77 | else 78 | let z3opts = new Dictionary() 79 | let s = new Solver() 80 | let p = s.Load(z3opts, inputs.[0]) 81 | 82 | // printfn "%s" inputs.[0] 83 | // dbg <| (lazy sprintf "%s" (p.ToString())) 84 | 85 | let solution = s.Solve p 86 | 87 | match solution with 88 | | SAT(m) -> 89 | if not (Verify p m) then 90 | printfn ("Error: Model verification failed.") 91 | exitStatus <- 30 92 | else 93 | printfn("sat") 94 | exitStatus <- 10 95 | | UNSAT -> 96 | printfn ("unsat") 97 | exitStatus <- 20 98 | | UNKNOWN -> 99 | printfn ("unknown") 100 | exitStatus <- 30 101 | with 102 | | :? System.StackOverflowException 103 | | :? System.OutOfMemoryException 104 | | :? Microsoft.Z3.Z3Exception as ex when ex.Message = "out of memory" -> 105 | // Ocassionally OutOfMemory exceptions are thrown from Z3, or from F# 106 | printfn "(error \"out of memory\")" 107 | exitStatus <- 30 108 | | :? System.AccessViolationException as ex -> 109 | // There is a rare case in which Z3 throws an access violation during 110 | // context destruction, could be a cleanup bug in Z3. 111 | // Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 112 | // at Microsoft.Z3.Native.LIB.Z3_del_context(IntPtr a0) 113 | // at Microsoft.Z3.Context.Finalize() 114 | if (ex.Message.Contains("Microsoft.Z3.Native.LIB.Z3_del_context") || 115 | ex.StackTrace.Contains("Microsoft.Z3.Native.LIB.Z3_del_context")) then 116 | printfn "Z3 cleanup problem ignored." 117 | () // keep previous exit status 118 | else 119 | exitStatus <- 30 120 | | Failure msg -> 121 | printfn "EXCEPTION: %s" msg 122 | printfn "UNKNOWN" 123 | exitStatus <- 30 124 | | ex -> 125 | printfn "EXCEPTION: %s: %s" ((ex.GetType()).ToString()) (ex.StackTrace.ToString()) 126 | printfn "UNKNOWN" 127 | exitStatus <- 30 128 | 129 | if INTERACTIVE then 130 | System.Console.ReadKey() |> ignore 131 | 132 | let time = System.DateTime.Now - before 133 | printfn "%f sec." time.TotalSeconds 134 | exitStatus // All done. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | bin/Debug/mcBV.exe: *.fs 3 | xbuild /p:Configuration=Debug mcBV-mono.fsproj 4 | 5 | bin/Release/mcBV.exe: *.fs 6 | xbuild /p:Configuration=Release mcBV-mono.fsproj 7 | 8 | debug: bin/Debug/mcBV.exe 9 | 10 | release: bin/Release/mcBV.exe 11 | 12 | all: debug release 13 | 14 | clean: 15 | rm -rf bin/Debug 16 | rm -rf bin/Release 17 | -------------------------------------------------------------------------------- /Model.fs: -------------------------------------------------------------------------------- 1 | module Model 2 | 3 | open BitVectorValuation 4 | open BooleanValuation 5 | 6 | type Model = class 7 | val bvValues : BitVectorValuation 8 | val boolValues : BooleanValuation 9 | 10 | new (bvs, bools) = { bvValues = bvs; boolValues = bools; } 11 | 12 | member this.getValueBool (i : int) = this.boolValues.getValueB i 13 | member this.getValueBV (i : int) = this.bvValues.getValue i 14 | end -------------------------------------------------------------------------------- /ModelVerification.fs: -------------------------------------------------------------------------------- 1 | module ModelVerification 2 | 3 | open Microsoft.Z3 4 | open System.Collections.Generic 5 | open GlobalOptions 6 | open Util 7 | open BooleanValuation 8 | open Problem 9 | open Model 10 | 11 | let verifySat (p:Problem) (m:Model) = 12 | let mutable finalRes = true 13 | let z3 = new Context(); 14 | let z3model = new Dictionary() 15 | let g = p.goal.Translate(z3) 16 | let vgoal = g.Translate(z3) 17 | 18 | for i in 1..p.var2expr.Length - 1 do 19 | if (p.var2expr.[i] <> null && 20 | p.var2expr.[i].IsConst) then 21 | if (p.var2expr.[i].IsBool) then 22 | let e = ((if ((m.getValueBool i) = True) then z3.MkTrue() else z3.MkFalse()) :> Expr) 23 | z3model.Add(p.var2expr.[i].Translate(z3), e.Translate(z3)) 24 | else 25 | let mutable mv = (m.getValueBV i) 26 | if not mv.isConcreteValue then 27 | mv <- mv.Minimum 28 | let e = mv.toZ3Expr z3 29 | z3model.Add(p.var2expr.[i].Translate(z3), e.Translate(z3)) 30 | 31 | let vars : Expr[] = Array.create z3model.Count null 32 | let values : Expr[] = Array.create z3model.Count null 33 | 34 | let mutable i = 0 35 | for kv in z3model do 36 | vars.[i] <- kv.Key 37 | values.[i] <- kv.Value 38 | i <- i + 1 39 | 40 | if SHOWMODEL then 41 | for kv in z3model do 42 | printfn "%s := %s" (kv.Key.ToString()) (kv.Value.ToString()) 43 | 44 | for i in 0 .. int(vgoal.Size) - 1 do 45 | let orig = vgoal.Formulas.[i] 46 | let subst = orig.Substitute(vars, values) 47 | let simple = subst.Simplify() 48 | if (simple.IsTrue) then 49 | if DBG then 50 | printfn "OK: %s -> %s -> %s" (orig.ToString()) (subst.ToString()) (simple.ToString()) 51 | else 52 | printfn "ERROR: %s -> %s -> %s" (orig.ToString()) (subst.ToString()) (simple.ToString()) 53 | finalRes <- false 54 | 55 | finalRes 56 | 57 | 58 | let Verify ( p : Problem ) ( m : Model ) = 59 | if not VERIFYMODEL then 60 | true 61 | else 62 | if not (verifySat p m) then 63 | false 64 | else 65 | polite <| (lazy "Ok, model verified.\n") 66 | true 67 | -------------------------------------------------------------------------------- /Numeral.fs: -------------------------------------------------------------------------------- 1 | module Numeral 2 | 3 | type Numeral = int 4 | 5 | let isNum (x:int) = x < 0 6 | 7 | -------------------------------------------------------------------------------- /NumeralDB.fs: -------------------------------------------------------------------------------- 1 | module NumeralDB 2 | 3 | open System.Collections.Generic 4 | open System.Numerics 5 | 6 | open Microsoft.Z3 7 | open Literal 8 | open GlobalOptions 9 | open BitVector 10 | open Stats 11 | open Stats 12 | 13 | type Num = int 14 | 15 | type NumeralDB private (size:int) = 16 | let mutable allocated = size 17 | let mutable reallocCoefficient = 2.0 18 | 19 | member val next_unused = 1 with get, set 20 | member val int2bv = Array.create allocated BitVector.Invalid with get, set 21 | member val bv2int = new Dictionary() with get, set 22 | 23 | new (expr2num:Dictionary) as this = 24 | NumeralDB(expr2num.Count + 1) 25 | then 26 | for kvp in expr2num do 27 | let id = abs kvp.Value 28 | assert(id > 0) 29 | if id >= this.next_unused then 30 | this.next_unused <- id + 1 31 | let num = BitVector.BitVectorFromExpr kvp.Key 32 | if this.int2bv.[id].isInvalid then 33 | assert(not (this.bv2int.ContainsKey num)) 34 | this.ensureSize (id + 1) 35 | this.bv2int.Add(num, id) 36 | this.int2bv.[id] <- num 37 | else 38 | assert(id <> 0) 39 | assert(this.int2bv.[id] = num) 40 | assert(this.bv2int.[num] = id) 41 | 42 | member r.ensureSize (minSize:int) = 43 | while allocated <= minSize do 44 | let newSize = int (reallocCoefficient * float allocated) 45 | r.int2bv <- Array.append r.int2bv (Array.create ((newSize + 1) - allocated) BitVector.Invalid) 46 | allocated <- newSize 47 | 48 | member r.newNumeral (stats:Ref) (num:BitVector) : Num = 49 | if r.bv2int.ContainsKey(num) then 50 | -r.bv2int.[num] 51 | else 52 | let mutable id = r.next_unused 53 | r.next_unused <- id + 1 54 | r.ensureSize (id + 1) 55 | assert(r.int2bv.[id].isInvalid) 56 | r.int2bv.[id] <- num 57 | r.bv2int.Add(num, id) 58 | if TRC then 59 | printfn "X New numeral: %d:num := %s" id (num.ToString()) 60 | (!stats).NewNumeral() 61 | -id 62 | 63 | member r.getNumeral (n:Num) = 64 | let id = abs n 65 | assert(id > 0 && id < r.int2bv.Length) 66 | let res = r.int2bv.[id] 67 | assert(res.isValid) 68 | res 69 | 70 | 71 | member val private inTempMode = false with get, set 72 | member val private snapshot = -1 with get, set 73 | 74 | member r.enterTempMode () = 75 | assert(not r.inTempMode) 76 | assert(r.snapshot = -1) 77 | r.inTempMode <- true 78 | r.snapshot <- r.next_unused 79 | 80 | member r.leaveTempMode = 81 | assert(r.inTempMode) 82 | assert(r.snapshot >= 0) 83 | for i in r.snapshot .. r.int2bv.Length - 1 do 84 | r.bv2int.Remove r.int2bv.[i] |> ignore 85 | r.int2bv.[i].markInvalid 86 | r.next_unused <- r.snapshot 87 | r.snapshot <- -1 88 | r.inTempMode <- false -------------------------------------------------------------------------------- /Preprocessing.fs: -------------------------------------------------------------------------------- 1 | module Preprocessing 2 | 3 | open Microsoft.Z3 4 | open System.Collections 5 | open System.Collections.Generic 6 | open GlobalOptions 7 | open Util 8 | 9 | let eliminateRelations (z3:Context) (e:Expr) (added_assertions : Ref< List >) = 10 | 11 | // CMW: Z3 has already rewritten x > y into not y <= x. We may want to rewrite that further? 12 | // if e.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_NOT then 13 | // let c = e.Args.[0] :?> BoolExpr 14 | // 15 | // if c.NumArgs > 1u && c.Args.[0].IsBV then 16 | // match c.FuncDecl.DeclKind with 17 | // | Z3_decl_kind.Z3_OP_ULEQ when c.Args.[0].IsBV -> 18 | // 19 | // | Z3_decl_kind.Z3_OP_SLEQ when c.Args.[0].IsBV -> 20 | // 21 | // | _ -> e 22 | // else 23 | // e 24 | 25 | if not (e.NumArgs = 2ul && e.Args.[0].IsBV && e.Args.[1].IsBV) then 26 | e 27 | else 28 | let x = e.Args.[0] :?> BitVecExpr 29 | let y = e.Args.[1] :?> BitVecExpr 30 | 31 | let size = x.SortSize 32 | let zero = z3.MkBV(0, size) 33 | let one = z3.MkBV(1, size) 34 | let signflip_pattern = (if size > 1u then 35 | (z3.MkConcat(z3.MkBV(1, 1u), z3.MkBV(0, size - 1u))) 36 | else 37 | z3.MkBV(1, 1u) :> BitVecExpr) 38 | let signflip = (fun x -> z3.MkBVAdd(x, signflip_pattern)) 39 | 40 | 41 | // We rewrite all comparison operators to unsigned less-than ULE 42 | match e.FuncDecl.DeclKind with 43 | | Z3_decl_kind.Z3_OP_ULEQ -> 44 | // OK, keep as is. 45 | e 46 | | Z3_decl_kind.Z3_OP_ULT -> 47 | // x < y <==> x <= y - 1 /\ y <> 0 48 | // CMW: I changed this from x < y <==> x + 1 <= y /\ x <> 11...11 to avoid the large 2^size 49 | let y_minus_1 = z3.MkBVSub(y, one) 50 | let x_le_y_minus_1 = z3.MkBVULE (x, y_minus_1) 51 | let y_non_zero = z3.MkNot(z3.MkEq(y, z3.MkBV(0, size))) 52 | ((z3.MkAnd ([| x_le_y_minus_1; y_non_zero|])) :> Expr) 53 | | Z3_decl_kind.Z3_OP_UGT -> 54 | // x > y <==> y <= x - 1 /\ x <> 0 55 | // CMW: I changed this from x + 1 <= y /\ x <> 11...11, to avoid the large 2^size 56 | let x_minus_1 = z3.MkBVSub(x, one) 57 | let y_le_x_minus_1 = z3.MkBVULE (y, x_minus_1) 58 | let x_non_zero = z3.MkNot(z3.MkEq(x, z3.MkBV(0, size))) 59 | ((z3.MkAnd ([| y_le_x_minus_1; x_non_zero |])) :> Expr) 60 | | Z3_decl_kind.Z3_OP_UGEQ -> 61 | // x >= y --> y <= x 62 | ((z3.MkBVULE (y, x)) :> Expr) 63 | 64 | | Z3_decl_kind.Z3_OP_SLEQ -> 65 | // x s<= y <==> xs u<= ys, where xs = (signflip x), ys = (signflip y) 66 | (z3.MkBVULE ((signflip x), (signflip y))) :> Expr 67 | | Z3_decl_kind.Z3_OP_SLT -> 68 | // x s< y <==> xs u< ys, where xs = (signflip x), ys = (signflip y) 69 | // <==> xs u<= ys - 1 /\ ys <> 00...0 70 | let x_flipped = (signflip x) 71 | let y_flipped = (signflip y) 72 | let y_minus_1 = z3.MkBVSub(y_flipped, one) 73 | let x_ule_y_minus_1 = z3.MkBVULE (x_flipped, y_minus_1) 74 | let y_non_zero = z3.MkNot(z3.MkEq(y_flipped, zero)) 75 | (z3.MkAnd ([| x_ule_y_minus_1; y_non_zero|])) :> Expr 76 | | Z3_decl_kind.Z3_OP_SGT -> 77 | // x s> y <==> y s< x 78 | // <==> ys u< xs, where xs = (signflip x), ys = (signflip y) 79 | // <==> ys u<= xs - 1 /\ xs <> 00...0 80 | let x_flipped = (signflip x) 81 | let y_flipped = (signflip y) 82 | let x_minus_1 = z3.MkBVSub(x_flipped, one) 83 | let y_ule_x_minus_1 = z3.MkBVULE (y_flipped, x_minus_1) 84 | let x_non_zero = z3.MkNot(z3.MkEq(x_flipped, zero)) 85 | (z3.MkAnd ([| y_ule_x_minus_1; x_non_zero |])) :> Expr 86 | | Z3_decl_kind.Z3_OP_SGEQ -> 87 | // x s>= y <==> (signflip ys) u<= (signflip xs) 88 | (z3.MkBVULE ((signflip y), (signflip x))) :> Expr 89 | 90 | | _ -> e 91 | 92 | 93 | let naryToBinary (z3:Context) (expr:Expr) (added_assertions:Ref< List >) = 94 | if expr.IsBV && expr.NumArgs > 2u then 95 | let folder = match expr.FuncDecl.DeclKind with 96 | | Z3_decl_kind.Z3_OP_BAND -> (fun x y -> z3.MkBVAND (x, y)) 97 | | Z3_decl_kind.Z3_OP_BOR -> (fun x y -> z3.MkBVOR (x, y)) 98 | | Z3_decl_kind.Z3_OP_BXOR -> (fun x y -> z3.MkBVXOR (x, y)) 99 | | Z3_decl_kind.Z3_OP_CONCAT -> (fun x y -> z3.MkConcat (x,y)) 100 | | Z3_decl_kind.Z3_OP_BADD -> (fun x y -> z3.MkBVAdd (x,y)) 101 | | Z3_decl_kind.Z3_OP_BMUL -> (fun x y -> z3.MkBVMul (x,y)) 102 | | _ -> NOT_YET_IMPLEMENTED(sprintf "nary->binary conversion for %s" (expr.FuncDecl.DeclKind.ToString())) 103 | 104 | let mutable current = expr.Args.[0] :?> BitVecExpr 105 | for i in 1 .. (int expr.NumArgs) - 1 do 106 | current <- folder current (expr.Args.[i] :?> BitVecExpr) 107 | let nn = z3.MkFreshConst("mcbv", current.FuncDecl.Range) 108 | (!added_assertions).Add(z3.MkEq(nn, current)) 109 | current <- nn :?> BitVecExpr 110 | 111 | current :> Expr 112 | else 113 | expr 114 | 115 | 116 | let eliminateDivI (z3:Context) (e:Expr) (added_assertions:Ref< List >) = 117 | // CMW: SDIV_I and UDIV_I are internal operations meaning BV division, where 118 | // div/0 has a fixed interpretation. That is the only division we support, 119 | // so we rewrite the DIV_I expressions to default B*DIV divisions. 120 | if (e.Args.Length = 2) then 121 | match (e.FuncDecl.Name.ToString()) with 122 | | "bvsdiv_i" -> z3.MkBVSDiv(e.Args.[0] :?> BitVecExpr, e.Args.[1] :?> BitVecExpr) :> Expr 123 | | "bvudiv_i" -> z3.MkBVUDiv(e.Args.[0] :?> BitVecExpr, e.Args.[1] :?> BitVecExpr) :> Expr 124 | | "bvsrem_i" -> z3.MkBVSRem(e.Args.[0] :?> BitVecExpr, e.Args.[1] :?> BitVecExpr) :> Expr 125 | | "bvurem_i" -> z3.MkBVURem(e.Args.[0] :?> BitVecExpr, e.Args.[1] :?> BitVecExpr) :> Expr 126 | | "bvsmod_i" -> z3.MkBVSMod(e.Args.[0] :?> BitVecExpr, e.Args.[1] :?> BitVecExpr) :> Expr 127 | | _ -> e 128 | else 129 | e 130 | 131 | 132 | let normalize (ht:Dictionary) (z3:Context) (e:Expr) (added_assertions:Ref< List >) = 133 | assert(e.IsBV || e.IsBool) 134 | 135 | let mk_new_args = fun args -> 136 | Array.map (fun (x:Expr) -> 137 | if x.IsConst || x.IsNumeral then x else 138 | match ht.TryGetValue x with 139 | | (true, y) -> y 140 | | (false, _) -> 141 | let y = z3.MkFreshConst("mcbv", x.FuncDecl.Range) 142 | ht.Add(x, y) 143 | (!added_assertions).Add(z3.MkEq(y, x)) 144 | y 145 | ) args 146 | 147 | if e.IsConst || e.IsNumeral then 148 | e 149 | elif (e.IsBool) then 150 | let allBVArgs = not (Array.exists (fun (x:Expr) -> not x.IsBV) e.Args) 151 | match e.FuncDecl.DeclKind with 152 | | Z3_decl_kind.Z3_OP_EQ 153 | | Z3_decl_kind.Z3_OP_ULEQ 154 | | Z3_decl_kind.Z3_OP_SLEQ 155 | | Z3_decl_kind.Z3_OP_ULT 156 | | Z3_decl_kind.Z3_OP_SLT 157 | | Z3_decl_kind.Z3_OP_UGEQ 158 | | Z3_decl_kind.Z3_OP_SGEQ 159 | | Z3_decl_kind.Z3_OP_UGT 160 | | Z3_decl_kind.Z3_OP_SGT when allBVArgs -> e.FuncDecl.Apply (mk_new_args e.Args) 161 | | _ -> e 162 | elif e.IsBV then 163 | e.FuncDecl.Apply (mk_new_args e.Args) 164 | else 165 | NOT_YET_IMPLEMENTED("non-bv operator") 166 | e 167 | 168 | 169 | let rewrite_f (z3:Context) (e:Expr) (added_assertions:Ref< List >) (f:Context -> Expr -> Ref< List > -> Expr) = 170 | let mutable stack = new Stack() 171 | let mutable cache = ref (Hashtable()) 172 | let caching_f = (fun (x:Expr) (s:Ref< Stack >) (c:Ref< Hashtable >) (aa:Ref< List >) -> 173 | let cached_value = if ((!c).ContainsKey(x)) then Some((!c).[x]) else None 174 | match cached_value with 175 | | Some(cv) -> c 176 | | _ -> 177 | let missing_args = (Array.fold 178 | (fun cnt y -> cnt + if not ((!c).ContainsKey(y)) then 1 else 0) 179 | 0 x.Args) 180 | if missing_args > 0 then 181 | (!s).Push(x) 182 | Array.map (fun y -> if not ((!c).ContainsKey(y)) then (!s).Push(y); ()) x.Args |> ignore 183 | c 184 | else 185 | let rcs_f = (fun (y:Expr) -> if not ((!c).ContainsKey(y)) then assert(false) 186 | let w = ((!c).[y]) :?> Expr 187 | w) 188 | let rcs = Array.map rcs_f x.Args 189 | let nx = (x.FuncDecl.Apply rcs) 190 | let rx = (f z3 nx aa) 191 | (!c).Add(x, rx) 192 | c 193 | ) 194 | stack.Push(e) |> ignore 195 | while stack.Count <> 0 do 196 | let ce = stack.Pop() 197 | cache <- (caching_f ce (ref stack) cache added_assertions) 198 | assert((!cache).ContainsKey(e)) 199 | (!cache).[e] 200 | 201 | 202 | let rewriteGoal (z3:Context) (g:Goal) (f:Context -> Expr -> Ref< List > -> Expr) = 203 | let newGoal = z3.MkGoal () 204 | 205 | let added_assertions = ref (List()) 206 | let forms = g.Formulas; 207 | for i in 0 .. forms.Length - 1 do 208 | let ge = forms.[i] 209 | trace <| (lazy sprintf "Rewriting: %s" ((ge :> Expr).ToString())) 210 | let rewritten = (rewrite_f z3 ge added_assertions f) :?> BoolExpr 211 | if (rewritten <> ge) then trace <| (lazy sprintf "Rewritten:\n %s\n to (goal index %d)\n %s" ((ge :> Expr).ToString()) i (rewritten.ToString())) 212 | newGoal.Assert(rewritten) 213 | for i in 0 .. (!added_assertions).Count - 1 do 214 | trace <| (lazy sprintf "Added assertion: %s" ((!added_assertions).[i].ToString())) 215 | newGoal.Assert((!added_assertions).[i]) 216 | 217 | newGoal 218 | 219 | 220 | let preprocess (z3:Context) (goal:Goal) = 221 | let solveEqsParams = z3.MkParams() 222 | solveEqsParams.Add("solve_eqs_max_occs", (uint32)2) 223 | let defaultParams = z3.MkParams() 224 | 225 | let mutable newGoal = goal 226 | 227 | verbose <| (lazy "Preprocessing/rewriting ...") 228 | 229 | if PREPROCESS then 230 | let simp2_p = z3.MkParams() 231 | simp2_p.Add("som", true) 232 | simp2_p.Add("pull_cheap_ite", true) 233 | simp2_p.Add("push_ite_bv", false) 234 | simp2_p.Add("local_ctx", true) 235 | simp2_p.Add("local_ctx_limit", (uint32)10000000) 236 | simp2_p.Add("flat", true) 237 | simp2_p.Add("hoist_mul", false) 238 | simp2_p.Add("hi_div0", true) 239 | 240 | 241 | let simpTac = z3.MkTactic("simplify") 242 | let preprocessing = [ z3.UsingParams(simpTac,simp2_p); 243 | z3.MkTactic("elim-term-ite"); 244 | z3.MkTactic("propagate-values"); 245 | z3.UsingParams(z3.MkTactic("solve-eqs"),solveEqsParams); 246 | simpTac; 247 | z3.MkTactic("elim-uncnstr"); 248 | z3.UsingParams(simpTac,simp2_p); 249 | z3.MkTactic("elim-term-ite"); 250 | z3.MkTactic("tseitin-cnf"); 251 | ] 252 | for tac in preprocessing do 253 | newGoal <- tac.Apply(newGoal,defaultParams).Subgoals.[0] 254 | 255 | newGoal <- rewriteGoal z3 newGoal eliminateRelations 256 | newGoal <- rewriteGoal z3 newGoal eliminateDivI 257 | newGoal <- rewriteGoal z3 newGoal (normalize (new Dictionary())) 258 | newGoal <- rewriteGoal z3 newGoal naryToBinary 259 | 260 | verbose <| (lazy "Preprocessing/rewriting done.") 261 | 262 | newGoal 263 | 264 | 265 | -------------------------------------------------------------------------------- /PriorityQueue.fs: -------------------------------------------------------------------------------- 1 | module PriorityQueue 2 | 3 | open System 4 | open System.Collections 5 | open System.Collections.Generic 6 | 7 | //Taken from: http://blogs.msdn.com/b/carlnol/archive/2012/05/03/net-implementation-of-a-priority-queue-aka-heap.aspx 8 | 9 | type PriorityQueue<'TKey, 'TValue when 'TKey : comparison> private (data:IEnumerable> option, capacity:int, comparer:IComparer<'TKey>) = 10 | 11 | let mutable heapList:List> = null 12 | let mutable positionDict:Dictionary<'TKey, ResizeArray> = null 13 | 14 | // Determines if a value is in the heap 15 | let inRange index = 16 | if index >= 0 && index < heapList.Count then Some(index) else None 17 | let checkIndex index = 18 | if ((inRange index).IsNone) then raise (ArgumentException(sprintf "Index specified is not within range - %i" index)) 19 | 20 | // Gets the children of a node 21 | let getChildren (index:int) = 22 | // children left[2*pos] and right[2*pos + 1] where pos = index + 1 23 | let left = (2 * index) + 1 24 | let right = (2 * index) + 2 25 | (inRange left, inRange right) 26 | 27 | // Gets the parent of an index 28 | let getParent (index:int) = 29 | // parent index [pos/2] where index = pos - 1 30 | if (index = 0) then None 31 | else Some((index-1) / 2) 32 | 33 | // Tests to see if the first value is greater than the first 34 | let isGreater parent child = 35 | if (comparer.Compare(heapList.[parent].Key, heapList.[child].Key) > 0) then true 36 | else false 37 | 38 | // Swaps two elements of the heap list 39 | let swapElements idx1 idx2 = 40 | let element1 = heapList.[idx1] 41 | let element2 = heapList.[idx2] 42 | heapList.[idx1] <- heapList.[idx2] 43 | heapList.[idx2] <- element1 44 | //positionDict.[element1.Key] <- idx2 45 | positionDict.[element1.Key].Remove(idx1) |> ignore 46 | positionDict.[element1.Key].Add(idx2) 47 | //positionDict.[element2.Key] <- idx1 48 | positionDict.[element2.Key].Remove(idx2) |> ignore 49 | positionDict.[element2.Key].Add(idx1) 50 | 51 | // Heapifys toward the parent 52 | let rec heapifyUp (index:int) = 53 | if (index > 0) then 54 | let parent = getParent index 55 | if (isGreater parent.Value index) then 56 | swapElements parent.Value index 57 | heapifyUp parent.Value 58 | 59 | // Heapifys down to the children 60 | let rec heapifyDown (index:int) = 61 | let (left, right) = getChildren index 62 | if (left.IsSome) then 63 | let childindex = 64 | if (right.IsSome && (isGreater left.Value right.Value)) then right.Value 65 | else left.Value 66 | if (isGreater index childindex) then 67 | swapElements index childindex 68 | heapifyDown childindex 69 | 70 | // Heapifys down to the children 71 | let heapifyUpDown (index:int) = 72 | let parent = getParent index 73 | if (parent.IsSome && (isGreater parent.Value index)) then 74 | heapifyUp index 75 | else 76 | heapifyDown index 77 | 78 | // Adds an items and heapifys 79 | let insertItem (key:'TKey) (value:'TValue) = 80 | let insertindex = heapList.Count 81 | //positionDict.Add(key, insertindex) 82 | if not (positionDict.ContainsKey(key)) then 83 | positionDict.Add(key, new ResizeArray()) 84 | positionDict.[key].Add(insertindex) 85 | heapList.Add(new KeyValuePair<'TKey, 'TValue>(key, value)) 86 | heapifyUp(insertindex) 87 | 88 | // Delete the root node and heapifys 89 | let deleteItem index = 90 | if (heapList.Count <= 1) then 91 | heapList.Clear() 92 | positionDict.Clear() 93 | else 94 | let lastindex = heapList.Count - 1 95 | let indexKey = heapList.[index].Key 96 | let lastKey = heapList.[lastindex].Key 97 | heapList.[index] <- heapList.[lastindex] 98 | //positionDict.[lastKey] <- index 99 | positionDict.[lastKey].Remove(lastindex) |> ignore 100 | positionDict.[lastKey].Add(index) 101 | heapList.RemoveAt(lastindex) 102 | //positionDict.Remove(indexKey) 103 | positionDict.[indexKey].Remove(index) |> ignore 104 | if (positionDict.[indexKey].Count = 0) then 105 | positionDict.Remove(indexKey) |> ignore 106 | heapifyDown index 107 | 108 | let powerTwo (value:int) = 109 | int (2.0 ** (float value)) 110 | 111 | // Merge new queue with original 112 | let mergeNewList (data:IEnumerable>) = 113 | data |> Seq.iter (fun item -> insertItem item.Key item.Value) 114 | 115 | let mergeNewListNoDup (data:IEnumerable>) = 116 | // Add list to the end of the queue 117 | let baseIdx = heapList.Count 118 | data |> Seq.iteri (fun idx item -> 119 | //positionDict.Add(item.Key, baseIdx + idx) 120 | if not (positionDict.ContainsKey(item.Key)) then 121 | positionDict.Add(item.Key, new ResizeArray()) 122 | positionDict.[item.Key].Add(baseIdx + idx) 123 | heapList.Add(new KeyValuePair<'TKey, 'TValue>(item.Key, item.Value))) 124 | // Now heapify the Queue from the bottom up 125 | let depth = int (Math.Log(float heapList.Count, 2.0)) 126 | for depthI = depth downto 1 do 127 | for index = ((powerTwo (depthI-1))-1) to ((powerTwo depthI)-2) do 128 | let (left, right) = getChildren index 129 | if (left.IsSome) then 130 | let childindex = 131 | if (right.IsSome && (isGreater left.Value right.Value)) then right.Value 132 | else left.Value 133 | if (isGreater index childindex) then 134 | swapElements index childindex 135 | 136 | // Default do bindings 137 | do 138 | if (comparer = null) then 139 | raise (ArgumentException("Comparer cannot be null")) 140 | 141 | let equalityComparer = 142 | { new IEqualityComparer<'TKey> with 143 | override x.Equals(c1, c2) = 144 | if ((comparer.Compare(c1, c2)) = 0) then true 145 | else false 146 | override x.GetHashCode(value) = 147 | value.GetHashCode() 148 | } 149 | 150 | heapList <- new List>(capacity) 151 | positionDict <- new Dictionary<'TKey, ResizeArray>(capacity, equalityComparer) 152 | 153 | if data.IsSome then 154 | //data.Value |> Seq.iter (fun item -> insertItem item.Key item.Value) 155 | mergeNewList data.Value 156 | 157 | // Set of constructors 158 | new() = PriorityQueue(None, 0, ComparisonIdentity.Structural<'TKey>) 159 | new(capacity:int) = PriorityQueue(None, capacity, ComparisonIdentity.Structural<'TKey>) 160 | new(data:IEnumerable>) = PriorityQueue(Some(data), 0, ComparisonIdentity.Structural<'TKey>) 161 | new(comparer:IComparer<'TKey>) = PriorityQueue(None, 0, comparer) 162 | new(capacity:int, comparer:IComparer<'TKey>) = PriorityQueue(None, capacity, comparer) 163 | new(data:IEnumerable>, comparer:IComparer<'TKey>) = PriorityQueue(Some(data), 0, comparer) 164 | 165 | // Checks to see if the heap is empty 166 | member this.IsEmpty 167 | with get() = (heapList.Count = 0) 168 | 169 | // Enqueues a new entry into the heap 170 | member this.Enqueue (key:'TKey) (value:'TValue) = 171 | insertItem key value 172 | () 173 | 174 | // Peeks at the head of the heap 175 | member this.Peek() = 176 | if not (this.IsEmpty) then 177 | heapList.[0] 178 | else 179 | raise (InvalidOperationException("Priority Queue is empty")) 180 | 181 | // Dequeues the head entry into the heap 182 | member this.Dequeue() = 183 | let value = this.Peek() 184 | deleteItem 0 185 | value 186 | 187 | // Determines whether an item is in the queue 188 | member this.Contains (key:'TKey) (value:'TValue) = 189 | if not (positionDict.ContainsKey key) then 190 | false 191 | else 192 | heapList.Contains(new KeyValuePair<'TKey, 'TValue>(key, value)) 193 | 194 | // Returns the index of a specified item 195 | member this.IndexOf (key:'TKey) (value:'TValue) = 196 | heapList.IndexOf(new KeyValuePair<'TKey, 'TValue>(key, value)) 197 | 198 | // Removes an item from the queue at the specified index 199 | member this.RemoveAt (index:int) = 200 | checkIndex index 201 | deleteItem index 202 | 203 | // Determines whether an item is in the queue 204 | member this.ContainsKey (key:'TKey) = 205 | positionDict.ContainsKey key 206 | 207 | // Gets the values associated with a Key 208 | member this.GetValues (key:'TKey) = 209 | if (positionDict.ContainsKey key) then 210 | positionDict.[key].ToArray() 211 | |> Array.map (fun index -> heapList.[index].Value) 212 | else 213 | Array.empty 214 | 215 | // Changes the key of a value in the queue 216 | member this.ChangeKey (key:'TKey) (value:'TKey)= 217 | let indexArray = positionDict.[key] 218 | indexArray.ToArray() 219 | |> Array.iter (fun index -> 220 | let item = heapList.[index] 221 | heapList.[index] <- new KeyValuePair<'TKey, 'TValue>(value, item.Value)) 222 | positionDict.Remove(key) |> ignore 223 | positionDict.Add(value, indexArray) 224 | indexArray.ToArray() 225 | |> Array.iter (fun index -> 226 | heapifyUpDown index) 227 | 228 | // Removes an item from the queue for the specified key 229 | member this.RemoveKey (key:'TKey) = 230 | let indexArray = positionDict.[key] 231 | indexArray.ToArray() 232 | |> Array.iter (fun index -> 233 | this.RemoveAt index) 234 | 235 | // Modifies elements based on index values 236 | member this.Item 237 | with get(index) = 238 | checkIndex index 239 | heapList.[index] 240 | and set(index) (value) = 241 | checkIndex index 242 | heapList.[index] <- new KeyValuePair<'TKey, 'TValue>(heapList.[index].Key, value) 243 | heapifyUpDown index 244 | 245 | // Returns the count of the queue 246 | member this.Count 247 | with get() = heapList.Count 248 | 249 | // Resets the capacity of the Queue 250 | member this.TrimExcess() = 251 | heapList.TrimExcess() 252 | 253 | // Returns the capacity of the queue 254 | member this.Capacity 255 | with get() = heapList.Capacity 256 | 257 | // Clears the queue 258 | member this.Clear() = 259 | heapList.Clear() 260 | 261 | // Merges an existing IEnumerable 262 | member this.Merge(data:IEnumerable>) = 263 | mergeNewList data 264 | 265 | member this.MergeNoDup(data:IEnumerable>) = 266 | mergeNewListNoDup data 267 | 268 | // Standard IList members 269 | interface ICollection> with 270 | 271 | member this.Add(item:KeyValuePair<'TKey, 'TValue>) = 272 | this.Enqueue item.Key item.Value 273 | 274 | member this.Clear() = 275 | heapList.Clear() 276 | 277 | member this.Contains(item:KeyValuePair<'TKey, 'TValue>) = 278 | if not (positionDict.ContainsKey item.Key) then 279 | false 280 | else 281 | heapList.Contains(item) 282 | 283 | member this.Count 284 | with get() = heapList.Count 285 | 286 | member this.CopyTo(toArray:KeyValuePair<'TKey, 'TValue>[], arrayIndex:int) = 287 | heapList.CopyTo(toArray, arrayIndex) 288 | 289 | member this.IsReadOnly 290 | with get() = false 291 | 292 | member this.Remove(item:KeyValuePair<'TKey, 'TValue>) = 293 | let index = heapList.IndexOf(item) 294 | if (inRange index).IsSome then 295 | deleteItem index 296 | true 297 | else 298 | false 299 | 300 | member this.GetEnumerator() = 301 | upcast heapList.GetEnumerator() 302 | 303 | // IEnumerable GetEnumerator implementation 304 | interface IEnumerable with 305 | member this.GetEnumerator() = 306 | upcast heapList.GetEnumerator() -------------------------------------------------------------------------------- /Problem.fs: -------------------------------------------------------------------------------- 1 | module Problem 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | 6 | type Problem = class 7 | val mutable goal : Goal 8 | val mutable vars : HashSet 9 | val mutable nums : HashSet 10 | val mutable maxVar : int 11 | val mutable maxNum : int 12 | val mutable var2expr : Expr[] 13 | val mutable var2sort : int[] 14 | val mutable expr2var : Dictionary 15 | val mutable num2id : Dictionary 16 | val mutable id2num : Expr[] 17 | 18 | new (g, vs, ns, v2e, v2s, e2v, n2i, i2n, mv, mn, dg) = 19 | { 20 | goal = g; 21 | vars = vs; 22 | nums = ns; 23 | maxVar = mv; 24 | maxNum = mn; 25 | var2expr = v2e; 26 | var2sort = v2s; 27 | expr2var = e2v; 28 | num2id = n2i; 29 | id2num = i2n; 30 | } 31 | 32 | override this.ToString() = 33 | this.goal.ToString() 34 | end -------------------------------------------------------------------------------- /PropagationRules.fs: -------------------------------------------------------------------------------- 1 | module PropagationRules 2 | 3 | open GlobalOptions 4 | open Util 5 | open Literal 6 | open BooleanValuation 7 | open Clause 8 | open Trail 9 | open State 10 | open WatchManager 11 | open TheoryRelation 12 | open BoundsTheory 13 | open RLEBVTheory 14 | 15 | 16 | let visitOccurrence (s:State) (tRel:Ref) = 17 | let pVal = s.bVal 18 | let boolVar = (!tRel).getBoolVar 19 | 20 | let T = (!pVal).getValueT boolVar 21 | let B = (!pVal).getValueB boolVar 22 | match (T, B) with 23 | 24 | // Check for conflicts 25 | | (True, False) 26 | | (False, True) -> 27 | // Note that valueT of boolVar could be a consequence of contraints in 28 | // either theory, but we don't know which one it is. Also, it could be 29 | // a cross-theory implication, in which case we need to know about 30 | // both theories' reasons. 31 | // See also tbndsImplyNewInterval, which creates cross-theory implications 32 | // (and so does trail.pushMA once we re-enable the negative PA case.) 33 | let tAnts = (tGetAntecedents s tRel) 34 | let tbndsAnts = if USE_BOUNDS then (tbndsGetAntecedents s tRel) else [] 35 | let c = newClauseFromList (tAnts @ tbndsAnts) 36 | // TODO: Cross-theory explanation generalization? 37 | // generalizeExplanation 38 | s.SetConflict (Some (ref c)) 39 | 40 | // For everything else we need to evaluate tRel 41 | | (Undefined, _) -> 42 | if not s.IsConflicted then 43 | if USE_BOUNDS && s.boundsEnabled then 44 | tbndsEvaluate s tRel 45 | tEvaluate s tRel 46 | 47 | | (True, Undefined) 48 | | (False, Undefined) -> 49 | assert(false) 50 | () 51 | 52 | | (True, True) -> () 53 | | (False, False) -> () 54 | 55 | 56 | let visitOccurrences (s:State) (v:Var) = 57 | let occCount = (!s.watchManager).getCount v 58 | 59 | let mutable i = 0 60 | while i < occCount && s.IsSearch do 61 | let w = (!s.watchManager).getPointer v i 62 | let wRel = (!s.theoryDB).getThRelationByIndex w 63 | 64 | let boolVar = wRel.getBoolVar 65 | let valB = ((!s.bVal).getValueB (boolVar)) 66 | let valT = ((!s.bVal).getValueT (boolVar)) 67 | trace <| (lazy sprintf " | o-see %s%s (B: %s T: %s)" 68 | (if valB = False then "not " else "") 69 | (wRel.ToString(s.numeralDB)) 70 | (valB.ToString()) 71 | (valT.ToString())) 72 | 73 | visitOccurrence s (ref wRel) 74 | 75 | i <- i + 1 76 | 77 | 78 | let bPropagate (s:State) (l:Literal) = 79 | let trail = !s.trail 80 | let cDB = !s.clauseDB 81 | let w = !s.watchManager 82 | let ind = w.getIndex(l) 83 | let mutable j = 0 //write ptr 84 | let mutable i = 0 //read ptr 85 | let cnt = w.getCount l 86 | 87 | // w.trcPrintWatch pCDB pTDB l true 88 | let mutable wcnt = 0 89 | while s.IsSearch && i < cnt do 90 | let clsPtr = w.getPtr ind i 91 | let c = (cDB.getClause clsPtr) 92 | let (newLit,wCnt) = findWatch l c s.bVal 93 | 94 | match wCnt with 95 | | Clause.Sat -> 96 | // Satisfied, just keep the clause 97 | trace <| (lazy sprintf " | b-see %d : %s (kept; %d is true)" clsPtr (clauseToString c) newLit) 98 | w.setPtr ind j (w.getPtr ind i) 99 | j <- j + 1 100 | wcnt <- wcnt + 1 101 | | Clause.Unknown -> 102 | // We have a new watch (on newLit, in position c.[2]) 103 | assert ((!s.bVal).getValueB (newLit) <> False) 104 | trace <| (lazy sprintf " | b-see %d : %s (migrated) to %d" clsPtr (clauseToString c) newLit) 105 | w.watchBool newLit clsPtr |> ignore 106 | wcnt <- wcnt + 1 107 | | Clause.Implication -> 108 | // Implication of newLit, which is in c.[1]; push onto trail 109 | trace <| (lazy sprintf " | b-see %d : %s (implication) of %d" clsPtr (clauseToString c) newLit) 110 | s.Push (Imp (cDB.getClauseRef clsPtr, newLit)) |> ignore 111 | // assert (not s.IsConflicted) // CMW: This is not true anymore; any Boolean variable can 112 | // be implied, but conflicting because of theory knowledge. But, I think this shouldn't 113 | // break anything. 114 | w.setPtr ind j (w.getPtr ind i) 115 | j <- j + 1 116 | wcnt <- wcnt + 17 117 | | Clause.Unsat -> 118 | // Conflict, but first compact the rest of this watch to maintain integrity 119 | trace <| (lazy sprintf " | b-see %d : %s unsatisfied" clsPtr (clauseToString c)) 120 | for k in i .. (cnt - 1) do 121 | let cid = (w.getPtr ind k) 122 | trace <| (lazy sprintf " | b-see %d : %s (kept/compacting)" cid (clauseToString (cDB.getClause cid))) 123 | w.setPtr ind j cid 124 | j <- j + 1 125 | s.SetConflict (Some (cDB.getClauseRef clsPtr)) 126 | wcnt <- wcnt + 1 127 | 128 | i <- i + 1 129 | 130 | w.setCount l j |> ignore 131 | 132 | if wcnt <> 0 then 133 | if (w.getWatchList l).Length = 0 then 134 | trace <| (lazy sprintf " | Watches for %d is empty." l) 135 | else 136 | trace <| (lazy sprintf " | Watches for %d are now: " l) 137 | w.trcPrintWatch s.numeralDB s.clauseDB s.theoryDB l true 138 | 139 | 140 | let PropagateTheories (s:State) (t:TrailElement) = 141 | match t with 142 | | MAssgnmnt (v,_, _) -> visitOccurrences s v 143 | | BAssgnmnt (v,_,_) -> visitOccurrences s v 144 | | _ -> () // Purely propositional Implication 145 | 146 | 147 | let Propagate (s:State) (t:TrailElement) = 148 | 149 | verbose <| (lazy sprintf "\\ Propagate %s :\n %s" 150 | 151 | (match t with 152 | | MAssgnmnt(v, _, _) -> "model assignment"//(sprintf "%d:bv = %s" v ((!s.bvVal).getValue(v).ToString())) 153 | | BAssgnmnt (v, _, _) -> "bounds"//(sprintf "%d:bv = %s" v ((!s.bounds).get(v).ToString())) 154 | | BoolDecision l -> "decision " + l.ToString() 155 | | Imp(e, l) -> "implication " + (clauseToString !e) + " -> "+ l.ToString()) 156 | 157 | //((!s.trail).ElementToString t) 158 | ( s.trailElemToString t)) 159 | 160 | // Propagate model assignments and theory relations 161 | PropagateTheories s t 162 | // Propagate Booleans and theory relation indicator variables 163 | if isBoolLiteral t && s.IsSearch then 164 | bPropagate s (getBoolLiteral t) 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | mcBV is a solver for (existential) bit-vector formulas (SMT QF_BV) based on the 4 | [mcSAT framework](http://dblp.org/rec/conf/vmcai/MouraJ13). 5 | 6 | The technical aspects and experimental results are described in: 7 | Zeljic, Wintersteiger, Ruemmer: [Deciding Bit-Vector Formulas with mcSAT] 8 | (http://research.microsoft.com/apps/pubs/default.aspx?id=264535). 9 | Proceedings of SAT, Springer, 2016. 10 | 11 | 12 | # Licence 13 | 14 | mcBV is licensed under the MIT licence (see [LICENSE.txt](LICENSE.txt)). 15 | 16 | 17 | # Requirements 18 | 19 | - [Visual Studio](https://www.visualstudio.com/) 20 | - [F#](http://fsharp.org/) 21 | - [Z3](https://github.com/Z3Prover/z3) 22 | 23 | # Contributing 24 | 25 | To contribute, you will need to complete a [Contributor License 26 | Agreement](https://cla.microsoft.com/) (CLA). Briefly, this agreement testifies 27 | that you are granting us permission to use the submitted change according to the 28 | terms of the project's license, and that the work being submitted is under 29 | appropriate copyright. 30 | -------------------------------------------------------------------------------- /Rules.fs: -------------------------------------------------------------------------------- 1 | module Rules 2 | 3 | open GlobalOptions 4 | open Util 5 | open BooleanValuation 6 | open Clause 7 | open Trail 8 | open State 9 | open RLEBVTheory 10 | open BoundsTheory 11 | open InitializationRules 12 | open PropagationRules 13 | open DecisionRules 14 | open ConflictRules 15 | open Explain 16 | open Z3Check 17 | 18 | let CheckTDB (s:State) = 19 | let mutable res = true 20 | for i in 0 .. (!s.theoryDB).count - 1 do 21 | let tRel = (!s.theoryDB).getThRelationByIndex i 22 | let tHolds = tHolds tRel s.bvVal s.numeralDB 23 | let tbndsHolds = tbndsHolds tRel s.bounds s.numeralDB 24 | let valueB = (!s.bVal).getValueB tRel.getBoolVar 25 | let valueT = (!s.bVal).getValueT tRel.getBoolVar 26 | 27 | match (tHolds, tbndsHolds, valueB, valueT) with 28 | | (Undefined, Undefined, _, Undefined) 29 | | (False, False, False, False) 30 | | (False, Undefined, False, False) 31 | | (True, True, True, True) 32 | | (True, Undefined, True, True) -> 33 | // That's alright, ignore. 34 | () 35 | | (True, _, False, _) 36 | | (True, _, _, False) 37 | | (False, _, True, _) 38 | | (False, _, _, True) 39 | | (_, _, True, False) 40 | | (_, _, False, True) -> 41 | let mutable is_propagated = false 42 | for c in (!s.trail).getTrailPtr .. (!s.trail).getCount - 1 do 43 | match (!s.trail).trail.[c] with 44 | | BoolDecision l 45 | | Imp (_,l) -> 46 | if abs l = tRel.getBoolVar then 47 | is_propagated <- true 48 | | MAssgnmnt (bv,_,_) -> 49 | if (List.exists (fun x -> x = bv) tRel.variableArguments) then 50 | is_propagated <- true 51 | | BAssgnmnt (bv,_,_) -> () 52 | if not is_propagated then 53 | printfn "Invariant violation; disagreement: %s -> (RLE:%s,Bnds:%s) x (B:%s,T:%s)" 54 | (tRel.ToString(s.numeralDB)) 55 | (tHolds.ToString()) 56 | (tbndsHolds.ToString()) 57 | (valueB.ToString()) 58 | (valueT.ToString()) 59 | res <- false 60 | 61 | | (True, _, Undefined, _) 62 | | (False, _, Undefined, _) -> 63 | let mutable is_propagated = false 64 | for c in (!s.trail).getTrailPtr .. (!s.trail).getCount - 1 do 65 | match (!s.trail).trail.[c] with 66 | | BoolDecision l 67 | | Imp (_,l) -> 68 | if abs l = tRel.getBoolVar then 69 | is_propagated <- true 70 | | MAssgnmnt (bv,_,_) -> if (List.exists (fun x -> x = bv) tRel.variableArguments) then 71 | is_propagated <- true 72 | | BAssgnmnt (bv,_,_) -> () 73 | if not is_propagated then 74 | // tRel holds, but that fact has not been propagated into the according 75 | // Boolean variable that represents tRel (tRel.getBoolVar) 76 | printfn "Not propagated to valueB %s" (tRel.ToString()) 77 | res <- false 78 | | (True, _, _, Undefined) 79 | | (False, _, _, Undefined) -> 80 | () // OK 81 | | (Undefined, True, _, _) 82 | | (Undefined, False, _, _) -> 83 | () // OK, bounds can be stronger 84 | | (Undefined, _, _, False) 85 | | (Undefined, _, _, True) -> 86 | printfn "Theory value assigned, but %s does not evaluate" (tRel.ToString()) 87 | res <- false 88 | | _ -> 89 | printfn "Theory DB check not implemented for tHolds=%s tbndsHolds=%s valueB=%s valueT=%s" (tHolds.ToString()) (tbndsHolds.ToString()) (valueB.ToString()) (valueT.ToString()) 90 | NOT_YET_IMPLEMENTED("th-rel check") 91 | 92 | if not res then 93 | printfn "Trail at the failure: " 94 | let mutable lvl = 0 95 | printfn "L%d====================================" lvl 96 | for i in 0 .. (!s.trail).getCount - 1 do 97 | let e = (!s.trail).trail.[i] 98 | match e with 99 | | BoolDecision v -> 100 | lvl <- lvl + 1 101 | printfn "L%d====================================" lvl 102 | printf "BoolDecision %d :" v 103 | | Imp (c,l) -> 104 | printf "(%s) -> %d : " (clauseToString !c) l 105 | | _ -> () 106 | 107 | printfn "%s" (s.trailElemToString e) 108 | res 109 | 110 | 111 | let paranoia (s:State) = 112 | let mutable res = true 113 | if not s.IsConflicted then 114 | res <- res && ((!s.clauseDB).Check s.bVal) 115 | res <- res && (CheckTDB s) 116 | res 117 | 118 | 119 | let PropagateWithLimitedBounds (s:State) (trail:Trail) = 120 | let mutable cnt = 0 121 | let limit = (!s.variableDB).highestVarInUse / 2 122 | while not s.IsConflicted && trail.hasPropagationsPending do 123 | Propagate s trail.nextPropagation 124 | cnt <- cnt + 1 125 | if cnt > limit then 126 | s.boundsEnabled <- false 127 | s.boundsEnabled <- true 128 | 129 | 130 | let checkSat (s:State) (sandbox:State) = 131 | let mutable trail = !s.trail 132 | 133 | // Initial propagation and watchlist construction 134 | pushUnits s 135 | 136 | // printfn "Stats: " 137 | // printfn "Vars : %d" (!s.varDB).highestVarInUse 138 | // printfn "BoolVars: %d" ((Array.sumBy (fun x -> if x = 0 then 1 else 0) (!s.varDB).sorts) - 1) 139 | // printfn "BvVars : %d" (Array.sumBy (fun x -> if x > 0 then 1 else 0) (!s.varDB).sorts) 140 | // printfn "Clauses : %d" (!s.clauseDB).count 141 | // printfn "Units : %d" (Array.sumBy (fun x -> 142 | // match x with 143 | // |Imp (cls,_) -> if getSize !cls = 1 then 1 else 0 144 | // | _ -> 0 ) (!s.trail).trail) 145 | 146 | dbg <| (lazy sprintf "%s" ((!s.clauseDB).ToString())) 147 | 148 | if DBG then 149 | printfn "Occurrence & watchlists: " 150 | let wm = (!s.watchManager) 151 | for v in 1 .. (!s.variableDB).highestVarInUse do 152 | if ((!s.variableDB).isBoolean v) then 153 | (wm.printBoolWatch s.clauseDB v) 154 | else 155 | (wm.printThWatch s.numeralDB s.theoryDB v) 156 | 157 | if s.IsConflicted then 158 | dbg <| (lazy sprintf "Conflict in initial clause database; trivially unsat.") 159 | dbg <| (lazy sprintf "Conflict clause: %s" (clauseToString !(s.GetConflictClause))) 160 | s.MarkUNSAT 161 | 162 | verbose <| (lazy sprintf "L 00 ===========================================================================") 163 | 164 | while not s.IsSolved do 165 | 166 | if s.IsConflicted then 167 | if (!s.trail).getNumDecisions = 0 then 168 | s.MarkUNSAT 169 | elif GENERALIZE then 170 | let pre_cnflct = !s.GetConflictClause 171 | assert(checkClauseIsFalse s.bVal pre_cnflct) 172 | xTExplanationGeneralization s sandbox 173 | 174 | if s.IsConflicted then 175 | let aft_cnflct = !s.GetConflictClause 176 | if pre_cnflct <> aft_cnflct then 177 | s.ShowFancyConflict(pre_cnflct, "[pre-generalization]") 178 | s.ShowFancyConflict(aft_cnflct, "[generalized]") 179 | else 180 | s.ShowFancyConflict(pre_cnflct, "[no generalization]") 181 | resolveConflict s 182 | //else 183 | //Otherwise Backjump-Decide resolved a conflict. 184 | else 185 | s.ShowFancyConflict(!s.GetConflictClause, "") 186 | resolveConflict s 187 | else 188 | // Propagation 189 | PropagateWithLimitedBounds s trail 190 | if DBG then assert(paranoia s) 191 | 192 | if s.IsSearch then 193 | if s.IsComplete then 194 | // Everything is assigned, so we're done. 195 | if not DBG then 196 | s.MarkSAT 197 | else 198 | if (paranoia s) then s.MarkSAT 199 | else 200 | // Decision time <- no propagagtions but search is incomplete, 201 | // i.e., at least one variable is still unassigned. 202 | let nd = trail.getNumDecisions + 1 203 | verbose <| (lazy sprintf "L %02d ===========================================================================" nd) 204 | decide s 205 | 206 | verbose <| (lazy sprintf "== Done ========================================================================") 207 | 208 | if VRB then 209 | if s.IsSatisfiable then 210 | printfn "SATISFIABLE" 211 | printfn "------------------" 212 | printfn "FINAL TRAIL:" 213 | (!s.trail).forcePrint("", s.bvVal, s.bounds) 214 | printfn "------------------" 215 | printfn "Model:" 216 | for v in 1 .. (!s.variableDB).highestVarInUse do 217 | if (!s.variableDB).sorts.[v] = 0 then 218 | printfn "%d -> %s" v (((!s.bVal).getValueB v).ToString()) 219 | else 220 | printfn "%d -> %s" v (((!s.bvVal).getValue v).ToString()) 221 | else if s.IsUnsatisfiable then 222 | (!s.trail).print("", s.bvVal, s.bounds) 223 | else 224 | verbose <| (lazy "UNKNOWN") 225 | 226 | s -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SandboxState.fs: -------------------------------------------------------------------------------- 1 | module SandboxState 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | open Literal 6 | open State 7 | open BooleanValuation 8 | open BitVectorValuation 9 | open BoundsValuation 10 | open Trail 11 | open Database 12 | open TheoryDB 13 | open WatchManager 14 | 15 | let prepareSandbox (odb:Database) = 16 | 17 | let initSize = (!odb.Variables).highestVarInUse 18 | let initSorts = (!odb.Variables).sorts 19 | let fTrail = Trail(initSize) 20 | let fBVal = BooleanValuation(initSize) 21 | let fPAssgnmnt = BitVectorValuation(initSize, initSorts) 22 | let fBounds = BoundsValuation(initSize, initSorts) 23 | //let fTheoryDB = TheoryDB(new Dictionary(),new Dictionary(), odb.Numerals, odb.Clauses) 24 | let fWatchMngr = WatchManager(initSize,10,odb.Theory) 25 | 26 | let mutable z3 : Context = new Context(new Dictionary()) 27 | let db = Database(odb.Numerals, odb.Variables, odb.Theory, ref fWatchMngr, z3.MkGoal(true,false,false)) 28 | z3.Dispose() 29 | State( initSize, 30 | ref fTrail, 31 | ref fBVal, 32 | ref fPAssgnmnt, 33 | ref fBounds, 34 | ref db) 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Solver.fs: -------------------------------------------------------------------------------- 1 | module Solver 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | 6 | open Model 7 | open GlobalOptions 8 | open Util 9 | open Preprocessing 10 | open State 11 | open BooleanValuation 12 | open BitVectorValuation 13 | open BoundsValuation 14 | open Trail 15 | open Database 16 | open Rules 17 | open Problem 18 | open SandboxState 19 | open Z3Check 20 | 21 | [] 22 | type Solution = SAT of Model | UNKNOWN | UNSAT 23 | 24 | type Solver = class 25 | new ( ) = { }; 26 | 27 | member this.Load (z3opts:Dictionary, filename:string ) = 28 | z3opts.Add("MODEL","true") 29 | let mutable z3 : Context = new Context(z3opts) 30 | 31 | let g = parseInput z3 filename 32 | 33 | trace <| (lazy sprintf "Unmodified goal: \n%s" (g.ToString())) 34 | 35 | let pg = (if filename.EndsWith ".smt2" then preprocess z3 g else g) 36 | let slvr = z3.MkSolver() in 37 | slvr.Add(pg.Formulas) ; 38 | trace <| (lazy sprintf "Preprocessed goal: \n%s" (slvr.ToString())) 39 | let vs = new HashSet() 40 | let ns = new HashSet() 41 | let (mv, mn, v2e, v2s, e2v, n2i, i2n) = mapVars pg vs ns 42 | 43 | // let z3Solver = this.z3.MkSolver("QF_BV") 44 | // z3Solver.Assert pg.Formulas 45 | // let res = z3Solver.Check () 46 | // if res = Status.SATISFIABLE then 47 | // printfn "Z3 says SAT" 48 | // else if res = Status.UNSATISFIABLE then 49 | // printfn "Z3 says UNSAT" 50 | // for e in z3Solver.UnsatCore do 51 | // printfn "%s" (e.ToString()) 52 | // else 53 | // printfn "Z3 says UNKNOWN" 54 | 55 | //new Problem(pg, vs, ns, v2e, v2s, e2v, n2i, i2n, mv, mn) 56 | 57 | if TRC then 58 | printfn "Variable map: " 59 | for i in 1 .. v2e.Length - 1 do 60 | if v2e.[i] = null then 61 | printfn "%d := NULL" i 62 | else 63 | if v2s.[i] = 0 then 64 | printfn "[%d] := Z3's %s " i (v2e.[i].ToString()) 65 | else 66 | printfn "%d:bv := Z3's %s " i (v2e.[i].ToString()) 67 | 68 | if DBG then 69 | printfn "Sorts:" 70 | for i in 1 .. v2s.Length - 1 do 71 | if v2s.[i] = 0 then 72 | printfn "Sort(%d) == Boolean" i 73 | else 74 | printfn "Sort(%d) == BitVec(%d)" i v2s.[i] 75 | 76 | if TRC then 77 | printfn "Numerals:" 78 | for i in 1 .. i2n.Length - 1 do 79 | let n = (i2n.[i] :?> BitVecNum) 80 | let sz = (n.Sort :?> BitVecSort).Size 81 | let nb = n.BigInteger 82 | printf "%d:num := #x%s" i (nb.ToString("X" + (sz/4ul).ToString())) 83 | if (sz % 4ul <> 0ul) then printf " (%s bit)" (sz.ToString()) 84 | printfn "" 85 | 86 | try 87 | z3.Dispose() 88 | System.GC.Collect() 89 | // System.GC.WaitForPendingFinalizers() 90 | // System.GC.WaitForFullGCComplete() |> ignore 91 | // System.GC.Collect() 92 | with 93 | | :? System.AccessViolationException as ex -> printfn("Context disposal exception ignored.") 94 | 95 | 96 | new Problem(pg, vs, ns, v2e, v2s, e2v, n2i, i2n, mv, mn, g) 97 | 98 | 99 | member this.Solve (p : Problem) = 100 | if p.goal.Formulas.Length = 1 && p.goal.Formulas.[0].IsFalse then 101 | polite <| (lazy "Solved by preprocessor\n") 102 | Solution.UNSAT 103 | else 104 | let fTrail = Trail(p.maxVar) 105 | let fBVal = BooleanValuation(p.maxVar) 106 | let fPAssgnmnt = BitVectorValuation(p.maxVar, p.var2sort) 107 | let fBounds = BoundsValuation(p.maxVar, p.var2sort) 108 | let db = Database(p.maxVar, p.num2id, p.var2sort, p.expr2var, p.goal) 109 | 110 | 111 | if p.goal.Formulas.Length = 0 then 112 | polite <| (lazy "Solved by preprocessor\n") 113 | Solution.SAT(new Model(fPAssgnmnt, fBVal)) 114 | else 115 | 116 | let initialState = 117 | State(p.maxVar, 118 | ref fTrail, 119 | ref fBVal, 120 | ref fPAssgnmnt, 121 | ref fBounds, 122 | ref db) 123 | 124 | let sbox = prepareSandbox db 125 | let s = checkSat initialState sbox 126 | 127 | 128 | if POLITE then 129 | (!(!s.database).Statistics).Print() 130 | 131 | if s.IsSatisfiable then 132 | Solution.SAT(new Model(!s.bvVal, !s.bVal)) 133 | else if s.IsUnsatisfiable then 134 | //checkUNSAT s.trail s.database s.bvVal s.bounds true 135 | Solution.UNSAT 136 | else 137 | Solution.UNKNOWN 138 | 139 | end 140 | 141 | -------------------------------------------------------------------------------- /State.fs: -------------------------------------------------------------------------------- 1 | module State 2 | 3 | open GlobalOptions 4 | open Learning 5 | open Util 6 | open Literal 7 | open Clause 8 | open Trail 9 | open Database 10 | open WatchManager 11 | open Z3Check 12 | open BooleanValuation 13 | open BitVectorValuation 14 | open BoundsValuation 15 | open VariableOrder 16 | open Stats 17 | 18 | 19 | type Answer = 20 | | Sat 21 | | Unsat 22 | | Unknown 23 | 24 | type State (maxVar:int, 25 | tr:Ref, 26 | tBoolValuation:Ref, 27 | tRLEValuation:Ref, 28 | tBndsValutation:Ref, 29 | db:Ref) = 30 | 31 | member val trail = tr 32 | member val bVal = tBoolValuation 33 | member val bvVal = tRLEValuation 34 | member val bounds = tBndsValutation 35 | member val database = db 36 | member val numeralDB = (!db).Numerals 37 | member val variableDB = (!db).Variables 38 | member val clauseDB = (!db).Clauses 39 | member val theoryDB = (!db).Theory 40 | member val watchManager = (!db).Watches 41 | member val private inTempMode = false with get, set 42 | member val private answer = Unknown with get, set 43 | member val private conflict : Ref Option = None with get, set 44 | member val private oldFlags = None with get, set 45 | 46 | member val boundsEnabled = true with get, set 47 | 48 | // AZ: Only to be used in sandbox 49 | member r.clearConflict () = 50 | r.conflict <- None 51 | 52 | member this.printConflict (conflict:Ref) = 53 | printf " | >C< " 54 | this.printClause conflict 55 | 56 | member this.printClause (clause:Ref)= 57 | (!this.trail).printClauseVerbose this.database clause 58 | // if DBG then printfn "--------------------------------------------------------------------------------" 59 | // if DBG then (!s.trail).forcePrint("", this.partAssignment, this.bounds) 60 | 61 | // AZ: The types mismatch, I know, but this is only for debugging purposes 62 | member this.printCube (cube:Ref)= 63 | (!this.trail).printCubeVerbose this.database cube 64 | // if DBG then printfn "--------------------------------------------------------------------------------" 65 | // if DBG then (!s.trail).forcePrint("", this.partAssignment, this.bounds) 66 | 67 | 68 | member this.Push (e:TrailElement) = 69 | let c = (!this.trail).Push this.bVal this.bvVal this.bounds this.database (!db).Statistics e 70 | match c with 71 | | Some(cc) -> this.SetConflict (Some cc) //xTheory conflict, detected during a push attempt. 72 | | None -> () 73 | 74 | member this.Pop = 75 | (!this.trail).Pop this.bVal this.bvVal this.bounds this.database 76 | 77 | member this.SetConflict (co:Ref option) = 78 | match co with 79 | | Some(cc) -> checkExplanation this.trail this.database this.bvVal this.bounds !cc false false true 80 | | None -> () 81 | this.conflict <- co 82 | 83 | member this.ClearConflict = 84 | this.conflict <- None 85 | 86 | member this.GetConflictClause = 87 | assert(this.conflict.IsSome) 88 | this.conflict.Value 89 | 90 | 91 | member this.IsComplete = 92 | let highest_var = (!this.variableDB).highestVarInUse 93 | let bool_vars_assigned = (!this.bVal).assignedVars 94 | let bv_vars_assigned = (!this.bvVal).assignedVars 95 | (highest_var = bool_vars_assigned + bv_vars_assigned) 96 | 97 | member this.IsConflicted = 98 | match this.conflict with 99 | | Some(_) -> true 100 | | None -> false 101 | 102 | member this.IsSearch = (not this.IsSolved) && this.conflict.IsNone 103 | member this.MarkSAT = this.answer <- Sat 104 | member this.MarkUNSAT = this.answer <- Unsat 105 | member this.MarkUNKNOWN = this.answer <- Unknown 106 | member this.IsSolved = this.answer = Sat || this.answer = Unsat 107 | member this.IsSatisfiable = this.answer = Sat 108 | member this.IsUnsatisfiable = this.answer = Unsat 109 | 110 | member this.Learn (c:Clause) = 111 | assert(not this.IsConflicted) 112 | let bVal = this.bVal 113 | if getSize(c) > 1 then 114 | dbg <| (lazy sprintf "* New clause: %s" (clauseToString c)) 115 | (!this.database).addAndWatchClause bVal c |> ignore 116 | else if getSize(c) = 1 && (!bVal).getValueB (c.[1]) = Undefined then 117 | (!this.clauseDB).addUnit c.[1] 118 | this.Push (Imp (ref c, c.[1])) 119 | assert(not this.IsConflicted) 120 | else if (getSize(c) = 1 && (!bVal).getValueB (c.[1]) = False) then 121 | //this.conflict <- Some (ref c) 122 | assert(false) 123 | else 124 | assert(c.[0] > 0) 125 | printfn "Warning attempted to add a redundant clause" 126 | 127 | member this.defineTseitinVariable (lits: Literal list) = 128 | 129 | let cls = newClauseFromList lits 130 | match (!this.clauseDB).getTseitinDefinition cls with 131 | | Some t -> t 132 | | None -> 133 | let tseitinVar = getTseitinVar this.database this.bVal this.bvVal this.bounds 134 | (!this.clauseDB).registerTseitin cls tseitinVar 135 | let tsVarImpliesGenLits = newClauseFromList ((Negate tseitinVar) :: lits) 136 | this.Learn tsVarImpliesGenLits 137 | for l in lits do 138 | this.Learn (newClauseFromList(Negate l :: tseitinVar :: [])) 139 | if DBG then printfn "Defining %d <--> %s" tseitinVar (clauseToString (newClauseFromList lits)) 140 | tseitinVar 141 | 142 | member r.enterTempMode (s:State)= 143 | //Some of the sanbox data structures might be out of date. 144 | //The database is shared so that is fine, 145 | //But bVal, bvVal, bounds 146 | assert (not r.inTempMode) 147 | r.inTempMode <- true 148 | let sortsRef = (ref (!s.variableDB).sorts) 149 | (!r.bVal).enterTempMode s.bVal 150 | (!r.bvVal).enterTempMode s.bvVal sortsRef 151 | (!r.bounds).enterTempMode s.bounds sortsRef 152 | (!r.database).enterTempMode (s.database) 153 | (!r.watchManager).enterTempMode (!s.variableDB).highestVarInUse 154 | 155 | member r.leaveTempMode() = 156 | assert (r.inTempMode) 157 | r.inTempMode <- false 158 | (!r.bVal).leaveTempMode 159 | (!r.bvVal).leaveTempMode 160 | (!r.bounds).leaveTempMode 161 | (!r.database).leaveTempMode() 162 | (!r.watchManager).leaveTempMode ((!r.variableDB).highestVarInUse) 163 | 164 | member r.isInTempMode = r.inTempMode 165 | 166 | member r.trailElemToString (t:TrailElement) = 167 | match t with 168 | | BAssgnmnt (v,_,_) -> let bnds = (!r.bounds).get v 169 | v.ToString() + ":bv \in " + (bnds.ToString()) 170 | | MAssgnmnt (v,_,_) -> let pattern = (!r.bvVal).getValue v 171 | v.ToString() + ":bv = " + (pattern.ToString()) 172 | | BoolDecision l 173 | | Imp (_,l) when (!r.theoryDB).isDefined (lit2var l) -> 174 | (if isNegated l then "not" else "") 175 | + ((!r.theoryDB).getThRelation (lit2var l)).ToString r.numeralDB 176 | | _ -> "" 177 | 178 | member r.ShowFancyConflict (cnflct:Clause, ?annotation:string) = 179 | if SHOW_CONFLICTS then 180 | assert (cnflct.Length > 0) 181 | assert (cnflct.Length = cnflct.[0] + 1) 182 | let nDB = (!r.database).Numerals 183 | let tDB = (!r.database).Theory 184 | 185 | printf "Conflict #%d: " !(!(!r.database).Statistics).conflicts 186 | match annotation with 187 | | None -> () 188 | | Some(a) -> printf " %s" a 189 | printfn "" 190 | 191 | let mutable first = true 192 | for i in 1 .. cnflct.Length - 1 do 193 | let l = cnflct.[i] 194 | let v = lit2var l 195 | if not ((!tDB).isDefined v) then 196 | if first then 197 | printf " " 198 | first <- false 199 | else 200 | printf " || " 201 | printf "%d" l 202 | if not first then printfn " || " 203 | 204 | first <- true 205 | for i in 1 .. cnflct.Length - 1 do 206 | let l = cnflct.[i] 207 | let v = (lit2var l) 208 | if (!tDB).isDefined v then 209 | if first then 210 | first <- false 211 | printf " " 212 | else 213 | printf " || " 214 | if l < 0 then 215 | printf "not " 216 | printfn "%s" (((!tDB).getThRelation v).ToString(nDB, false)) 217 | printfn "" -------------------------------------------------------------------------------- /Stats.fs: -------------------------------------------------------------------------------- 1 | module Stats 2 | 3 | open System.Collections.Generic 4 | open Microsoft.Z3 5 | 6 | type Statistics () = 7 | member val propagations = ref 0 8 | member val conflicts = ref 0 9 | member val decisions = ref 0 10 | member val modelAssignments = ref 0 11 | member val intrThLits = ref 0 12 | member val intrNumerals = ref 0 13 | 14 | member r.Implication() = 15 | incr r.propagations 16 | 17 | member r.Conflict() = 18 | incr r.conflicts 19 | 20 | member r.Decision() = 21 | incr r.decisions 22 | 23 | member r.ModelAssignment() = 24 | incr r.modelAssignments 25 | 26 | member r.NewThLiteral() = 27 | incr r.intrThLits 28 | 29 | member r.NewNumeral() = 30 | incr r.intrNumerals 31 | 32 | member r.Print() = 33 | printfn "+------- Statistics --------+" 34 | printfn "| Decisions : % 10d |" (!r.decisions) 35 | printfn "| Propagations : % 10d |" (!r.propagations) 36 | printfn "| Conflicts : % 10d |" (!r.conflicts) 37 | printfn "| MAssignments : % 10d |" (!r.modelAssignments) 38 | printfn "| Theory Lits : % 10d |" (!r.intrThLits) 39 | printfn "| Numerals : % 10d |" (!r.intrNumerals) 40 | printfn "+---------------------------+" 41 | -------------------------------------------------------------------------------- /TheoryDB.fs: -------------------------------------------------------------------------------- 1 | module TheoryDB 2 | 3 | open Microsoft.Z3 4 | open System.Collections.Generic 5 | open Util 6 | open Literal 7 | open NumeralDB 8 | open TheoryRelation 9 | open ClauseDB 10 | 11 | 12 | type TheoryDB private () = 13 | let reallocCoefficient = 0.5 14 | 15 | new (expr2var, num2id, n, c) as this = 16 | TheoryDB() 17 | then 18 | this.init expr2var num2id n c 19 | 20 | member val thRels = ([||]:TheoryRelation []) with get, set 21 | member val private allocatedSize = 0 with get, set 22 | member val count = 0 with get, set 23 | member val private originalSize = 0 with get, set 24 | 25 | // member val introducedRelations = new Dictionary() with get, set 26 | member val introducedEQs = new Dictionary() with get, set 27 | member val introducedLEQs = new Dictionary() with get, set 28 | 29 | member val bool2ThRel = new Dictionary() with get, set 30 | member val private inTempMode = false with get, set 31 | member val private snapshot = -1 with get, set 32 | 33 | member private r.init (expr2var:Dictionary) (num2id:Dictionary) (nDB:ref) (cDB:ref) = 34 | let cnt = ref 0 35 | 36 | for e in expr2var.Keys do 37 | if isBoolRelation e || (e.IsBV && e.NumArgs > 0u) then 38 | incr cnt 39 | 40 | r.thRels <- Array.create !cnt EmptyThRel 41 | r.allocatedSize <- !cnt 42 | r.count <- 0 43 | r.originalSize <- !cnt 44 | 45 | dbg <| (lazy "Theory relations:") 46 | for e in expr2var.Keys do 47 | if isBoolRelation e then 48 | let t = thRelFromRel expr2var num2id nDB e 49 | if not (r.isIntroduced t) then 50 | r.add t |> ignore 51 | else if e.IsBV && e.NumArgs > 0u then 52 | let t = newThRelFromBVOP expr2var num2id nDB e 53 | if not (r.isIntroduced t) then 54 | r.add t |> ignore 55 | (!cDB).addUnit t.getBoolVar 56 | 57 | 58 | member private r.reallocate () = 59 | assert (r.allocatedSize > 0) //This ensures that init ran before first reallocation 60 | 61 | let desired = int (reallocCoefficient * (float r.allocatedSize)) 62 | let sizeIncrement = if desired = 0 then 1 else desired 63 | r.thRels <- Array.append r.thRels (Array.create sizeIncrement EmptyThRel) 64 | r.allocatedSize <- r.allocatedSize + sizeIncrement 65 | 66 | member private r.isLegal (ind:int) = 67 | 0 <= ind && ind <= r.count 68 | 69 | member r.getThRelationByIndex(i:int) = 70 | assert (r.isLegal i) 71 | r.thRels.[i] 72 | 73 | member private r.getThRelationRefByIndex(i:int) = 74 | assert (r.isLegal i) 75 | ref r.thRels.[i] 76 | 77 | member r.getThRelRef(i:int) = 78 | assert (r.isLegal i) 79 | ref (r.thRels.[i]) 80 | 81 | member r.getThRelation (boolVar:int) = 82 | assert (r.isDefined boolVar) 83 | let relInd = r.bool2ThRel.[boolVar] 84 | r.getThRelationByIndex relInd 85 | 86 | member r.getThRelationReference (boolVar:int) = 87 | assert (r.isDefined boolVar) 88 | let relInd = r.bool2ThRel.[boolVar] 89 | r.getThRelationRefByIndex relInd 90 | 91 | member r.getThRelationVar (t:TheoryRelation) = 92 | if t.getRelationOP = Z3_decl_kind.Z3_OP_EQ then 93 | match r.introducedEQs.TryGetValue t with 94 | | (true, boolVar) -> (true, boolVar) 95 | | (false, _) -> (false, 0) 96 | else 97 | match r.introducedLEQs.TryGetValue t with 98 | | (true, boolVar) -> (true, boolVar) 99 | | (false, _) -> (false, 0) 100 | 101 | member r.isDefined (b:Var) = 102 | r.bool2ThRel.ContainsKey b 103 | 104 | member r.mapBooleanToThRel (b:Var) (ind:int) = 105 | assert (not (r.isDefined b)) 106 | r.bool2ThRel.Add(b, ind) 107 | 108 | member r.isIntroduced (t:TheoryRelation) = 109 | if (t.getRelationOP = Z3_decl_kind.Z3_OP_EQ) then 110 | (r.introducedEQs.ContainsKey t) 111 | else 112 | (r.introducedLEQs.ContainsKey t) 113 | 114 | //Intended use: 115 | // we have a new clause to add, either through learning or a generated explanation or w/e 116 | // 1. Add the clause, obtain its pointer in the DB 117 | // 2. Run getWatches over the reference and add the pointers where necessary 118 | member r.add (t:TheoryRelation) : int = 119 | assert(not (r.isIntroduced t)) 120 | if r.count = r.allocatedSize then 121 | r.reallocate () 122 | 123 | let index = r.count 124 | r.thRels.[index] <- t 125 | r.count <- r.count + 1 126 | r.mapBooleanToThRel t.getBoolVar index 127 | if t.getRelationOP = Z3_decl_kind.Z3_OP_EQ then 128 | r.introducedEQs.Add(t, t.getBoolVar) 129 | else 130 | assert(t.getRelationOP = Z3_decl_kind.Z3_OP_ULEQ) 131 | r.introducedLEQs.Add(t, t.getBoolVar) 132 | index 133 | 134 | member r.enterTempMode () = 135 | assert(not r.inTempMode) 136 | assert(r.snapshot = -1) 137 | r.inTempMode <- true 138 | r.snapshot <- r.count 139 | 140 | member r.leaveTempMode = 141 | assert(r.inTempMode) 142 | assert(r.snapshot >= 0) 143 | for i in r.snapshot .. r.count - 1 do 144 | let t = r.getThRelationByIndex i 145 | assert(r.isIntroduced t) 146 | if (t.getRelationOP = Z3_decl_kind.Z3_OP_EQ) then 147 | r.introducedEQs.Remove t |> ignore 148 | else 149 | r.introducedLEQs.Remove t |> ignore 150 | r.bool2ThRel.Remove t.getBoolVar |> ignore 151 | 152 | r.count <- r.snapshot 153 | r.snapshot <- -1 154 | r.inTempMode <- false -------------------------------------------------------------------------------- /Util.fs: -------------------------------------------------------------------------------- 1 | module Util 2 | 3 | open Microsoft.Z3 4 | open System.Collections 5 | open System.Collections.Generic 6 | open System.Numerics 7 | open GlobalOptions 8 | 9 | let dbg (x:Lazy) = 10 | if DBG then 11 | printfn "%s" (x.Force()) 12 | 13 | let trace (x:Lazy) = 14 | if TRC then 15 | printfn "%s" (x.Force()) 16 | 17 | let verbose (x:Lazy) = 18 | if VRB then 19 | printfn "%s" (x.Force()) 20 | 21 | let polite (x:Lazy) = 22 | if POLITE then 23 | printf "%s" (x.Force()) 24 | 25 | let NOT_YET_IMPLEMENTED (s:string) = 26 | failwith ("NYI: " + s) 27 | 28 | let UNREACHABLE (s:string) = 29 | failwith ("Unreachable code reached: " + s) 30 | 31 | let UNSOUND (s:string) = 32 | failwith ("Unreachable code reached: " + s) 33 | 34 | let rec collectCnsts (sortDic:Dictionary) (fla:Expr) = 35 | if fla.IsApp && fla.NumArgs = 0u then 36 | if not (sortDic.ContainsKey(fla.ToString())) then 37 | sortDic.Add(fla.ToString(),fla.FuncDecl.Range) 38 | [fla] 39 | else 40 | [] 41 | else 42 | Array.map (collectCnsts sortDic) (fla.Args) 43 | |> Array.fold (fun x y -> x @ y) [] 44 | 45 | let isBoolRelation (f:Expr) = 46 | match f.FuncDecl.DeclKind with 47 | | Z3_decl_kind.Z3_OP_EQ 48 | | Z3_decl_kind.Z3_OP_SLEQ 49 | | Z3_decl_kind.Z3_OP_SLT 50 | | Z3_decl_kind.Z3_OP_SGEQ 51 | | Z3_decl_kind.Z3_OP_SGT 52 | | Z3_decl_kind.Z3_OP_ULEQ 53 | | Z3_decl_kind.Z3_OP_ULT 54 | | Z3_decl_kind.Z3_OP_UGEQ 55 | | Z3_decl_kind.Z3_OP_UGT 56 | -> true 57 | | _ -> false 58 | 59 | let isBVsort (f:Expr) = 60 | match f.FuncDecl.Range.SortKind with 61 | | Z3_sort_kind.Z3_BV_SORT -> true 62 | | _ -> false 63 | 64 | 65 | // CMW: `collectVars`: bad function name. It does much more than just to collect variables. 66 | let rec collectVars (vars:HashSet) (numerals:HashSet) (flag:bool) (fla:Expr) = 67 | // CMW: Variable `flag`: bad name. What are the semantics? 68 | // CMW: Variable `fla`: bad name, hard to guess what it means; better: `frmla`, but there's 69 | // really no goood reason not to call it `formula`. 70 | if fla.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_BNUM then 71 | numerals.Add(fla) |> ignore 72 | else 73 | if isBoolRelation fla then 74 | Array.map (collectVars vars numerals false) fla.Args |> ignore 75 | 76 | if not (vars.Contains fla) && flag then 77 | vars.Add(fla) |> ignore 78 | else 79 | Array.map (collectVars vars numerals true) fla.Args |> ignore 80 | 81 | if not (vars.Contains fla) && 82 | fla.FuncDecl.DeclKind <> Z3_decl_kind.Z3_OP_NOT && 83 | fla.FuncDecl.DeclKind <> Z3_decl_kind.Z3_OP_OR && 84 | (flag || fla.NumArgs = 0u) then 85 | vars.Add(fla) |> ignore 86 | 87 | 88 | // CMW: `mapVars`: bad function name. It does much more than just to map variables. 89 | let rec mapVars (g:Goal) (vars:HashSet) (numerals:HashSet) = 90 | Array.map (collectVars vars numerals true) g.Formulas |> ignore 91 | let toBeIntroduced = Array.sum [|for v in vars do yield if v.IsBV && v.NumArgs > 0u then 1 else 0|] 92 | let expr2var = new Dictionary() 93 | let num2id = new Dictionary() 94 | let id2num = Array.create (numerals.Count + 1) null 95 | let var2expr = Array.create (vars.Count + 1 + toBeIntroduced) null 96 | let sorts = Array.create (vars.Count + 1 + toBeIntroduced) 0 97 | let mutable i = 1 98 | for e in vars do 99 | var2expr.[i] <- e 100 | expr2var.Add(e,i) 101 | if e.IsBV then 102 | match e.FuncDecl.Range with 103 | | :? BitVecSort as bvSort -> sorts.[i] <- int bvSort.Size 104 | | _ -> UNREACHABLE("Error: Unable to obtain BV sort for a BV variable") 105 | if e.NumArgs > 0u then //Implicit equality, we need to introduce a boolean variable for it, it will have value var + 1 106 | i <- i + 1 107 | var2expr.[i] <- null //placeholder, sort is bool by initialization of the sort array 108 | i <- i + 1 109 | let mutable j = 1 110 | for e in numerals do 111 | id2num.[j] <- e 112 | num2id.Add(e, - j) 113 | j <- j + 1 114 | 115 | (i - 1, j - 1, var2expr, sorts, expr2var, num2id, id2num) 116 | 117 | 118 | let collectConstants (g:Goal) (consts:Dictionary) = 119 | let exprList = Array.map (collectCnsts consts) g.Formulas 120 | |> Array.fold (fun x y -> x @ y) [] 121 | exprList 122 | 123 | let collectLiterals (e:Expr) = 124 | if e.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_OR then 125 | [for c in e.Args -> c] 126 | else 127 | [e] 128 | 129 | let removeNegation (e : Expr) = 130 | if e.FuncDecl.DeclKind = Z3_decl_kind.Z3_OP_NOT then 131 | e.Args.[0] 132 | else 133 | e 134 | 135 | let makeZ3Lit (z3:Context) (l:int) = 136 | if l > 0 then 137 | (z3.MkConst(l.ToString(), z3.MkBoolSort()):?> BoolExpr) 138 | else 139 | z3.MkNot((z3.MkConst((abs l).ToString(), z3.MkBoolSort())) :?> BoolExpr) 140 | 141 | let initVars (z3:Context) (v:int) = 142 | for i in 1 .. v do 143 | z3.MkFreshConst(i.ToString(),z3.BoolSort) |> ignore 144 | 145 | 146 | let parseDimacs (z3:Context) (fn:string) = 147 | let lines = System.IO.File.ReadLines(fn) 148 | let mutable clsNum = 0 149 | let mutable varNum = 0 150 | let mutable vars = null 151 | let goal = z3.MkGoal(true,false,false) 152 | for (l:string) in lines do 153 | if l.Length > 0 then 154 | match l.Chars 0 with 155 | | 'c' -> () 156 | | '%' -> () 157 | | '0' -> () 158 | | 'p' -> let a = Array.filter (fun (x:string) -> x.Length > 0 && not (x.Equals("p")) && not (x.Equals("cnf"))) (l.Split([|' '|])) 159 | varNum <- int a.[0] 160 | clsNum <- int a.[1] 161 | initVars z3 varNum 162 | | _ -> let a = l.Split([|' '|]) |> Array.filter (fun (x:string) -> x.Length > 0) 163 | |> Array.map (fun x -> int x) 164 | |> Array.toSeq 165 | |> Seq.takeWhile (fun x -> x <> 0) 166 | |> Seq.toArray 167 | |> Array.map (makeZ3Lit z3) 168 | goal.Add(z3.MkOr((a))) 169 | goal 170 | 171 | let parseInput (z3:Context) (fileName:string) = 172 | verbose <| (lazy "Parsing...") 173 | let r = if fileName.EndsWith(".smt2") then 174 | let g = z3.MkGoal(true,false,false) 175 | let p = z3.ParseSMTLIB2File(fileName, [||],[||],[||],[||]) 176 | g.Add(p) 177 | g 178 | else 179 | parseDimacs z3 (fileName) 180 | verbose <| (lazy " done.") 181 | r 182 | 183 | 184 | let BigIntegerToBinaryString (b:BigInteger) (ss:uint32) : string = 185 | assert(ss > 0ul) 186 | let mutable res = "" 187 | let mutable tmp = b; 188 | let two = BigInteger(2) 189 | for i in 1ul .. ss do 190 | res <- (tmp % two).ToString() + res 191 | tmp <- tmp / two 192 | res -------------------------------------------------------------------------------- /VariableDB.fs: -------------------------------------------------------------------------------- 1 | module VariableDB 2 | 3 | open Microsoft.Z3 4 | open System.Collections.Generic 5 | open GlobalOptions 6 | open Util 7 | open Literal 8 | open VariableOrder 9 | 10 | 11 | 12 | type VariableDB private (size:int) = 13 | //Handles variables that are currently in use 14 | //Boolean and BitVector variables are mixed up 15 | //Sorts will make the distinction between boolean and bv mvars 16 | 17 | let reallocCoefficient = 0.5 18 | 19 | new (var2sort:VarType[]) as this = 20 | let size = var2sort.Length - 1 21 | VariableDB (size) 22 | then 23 | this.sorts <- var2sort 24 | for i in 1 .. this.highestVarInUse do 25 | if var2sort.[i] > 0 then 26 | this.varOrder.insert i false 27 | else 28 | this.varOrder.insert i true 29 | 30 | member val originalSize = size + 1 31 | member val allocatedSize = size + 1 with get,set 32 | 33 | // Dictates the size of the sort array 34 | member val highestVarInUse = size with get, set 35 | member val private inTempMode = false with get, set 36 | member val private snapshot = -1 with get, set 37 | member val varOrder : VariableOrder = new VariableOrder() 38 | member val sorts = [||] with get, set 39 | 40 | member private r.isLegal (v:int) = 0 < v && v <= r.highestVarInUse 41 | 42 | member private r.reallocate () = 43 | let sizeIncrement = int (reallocCoefficient * (float r.allocatedSize)) 44 | r.sorts <- Array.append r.sorts (Array.zeroCreate sizeIncrement) 45 | r.allocatedSize <- r.allocatedSize + sizeIncrement 46 | 47 | member r.isBoolean (v:int) = 48 | assert (r.isLegal v) 49 | r.sorts.[v] = 0 50 | 51 | member r.isBitVector (v:int) = 52 | assert (r.isLegal v) 53 | r.sorts.[v] > 0 54 | 55 | member r.getBitVectorLength (v:int) = 56 | assert (r.isLegal v) 57 | r.sorts.[v] 58 | 59 | member r.newBooleanVariable () = 60 | if r.highestVarInUse + 1 = r.allocatedSize then 61 | r.reallocate () 62 | 63 | r.highestVarInUse <- r.highestVarInUse + 1 64 | r.varOrder.insert r.highestVarInUse true 65 | r.highestVarInUse 66 | 67 | member r.newBitVectorVariable (len:int) = 68 | if r.highestVarInUse + 1 = r.allocatedSize then 69 | r.reallocate () 70 | 71 | r.highestVarInUse <- r.highestVarInUse + 1 72 | let v = r.highestVarInUse 73 | r.sorts.[v] <- len 74 | r.varOrder.insert v false 75 | v 76 | 77 | 78 | 79 | member r.getSnapshot = r.snapshot 80 | 81 | member r.enterTempMode () = 82 | assert(not r.inTempMode) 83 | assert(r.snapshot = -1) 84 | r.inTempMode <- true 85 | r.varOrder.enterTempMode() 86 | r.snapshot <- r.highestVarInUse 87 | 88 | member r.leaveTempMode = 89 | assert(r.inTempMode) 90 | assert(r.snapshot >= 0) 91 | // for i in r.snapshot + 1 .. r.highestVarInUse do 92 | // r.varOrder.remove i 93 | r.varOrder.leaveTempMode 94 | r.highestVarInUse <- r.snapshot 95 | r.snapshot <- -1 96 | r.inTempMode <- false 97 | 98 | 99 | member r.print () = 100 | if DBG then 101 | printfn "" 102 | printfn "-------------------" 103 | printfn "|Variable database|" 104 | printfn "-------------------" 105 | printfn "Allocated: %d MaxVar: %d " r.allocatedSize r.highestVarInUse 106 | for v in 1 .. r.highestVarInUse do 107 | if r.isBoolean v then 108 | printfn "%d : Bool" v 109 | else 110 | printfn "%d : BitVector %d" v r.sorts.[v] 111 | -------------------------------------------------------------------------------- /VariableOrder.fs: -------------------------------------------------------------------------------- 1 | module VariableOrder 2 | 3 | open System.Collections.Generic 4 | open PriorityQueue 5 | open Literal 6 | 7 | 8 | type VariableOrder () = class 9 | let initBvValue = 100000 10 | let initBoolValue = 99900 11 | let resetValue = 100001 12 | let increment = 1 13 | 14 | let step = 500 15 | let mutable allocated = 11 // 1 to account for L 0 being reserved 16 | let mutable priorities = Array.create allocated resetValue 17 | let mutable queue = new PriorityQueue () 18 | 19 | member val private inTempMode = false with get, set 20 | 21 | member r.enterTempMode () = 22 | assert(not r.inTempMode) 23 | r.inTempMode <- true 24 | 25 | member r.leaveTempMode = 26 | assert(r.inTempMode) 27 | r.inTempMode <- false 28 | 29 | member private this.insertPriority (v:Var) (p:int) = 30 | if v >= allocated then 31 | priorities <- Array.append priorities (Array.create step resetValue) 32 | allocated <- allocated + step 33 | 34 | priorities.[v] <- p 35 | 36 | member private this.getPriority (v:Var) = 37 | assert (v < allocated) 38 | priorities.[v] 39 | 40 | member private this.setPriority (v:Var) (p:int) = 41 | assert (v < allocated) 42 | priorities.[v] <- p 43 | 44 | member this.insert (v:Var) (isBool:bool) = 45 | if not this.inTempMode then 46 | assert (v <> 0) 47 | let iv = if isBool then initBoolValue else initBvValue 48 | assert (v >= allocated || this.getPriority v = resetValue) 49 | assert (not (queue.Contains iv v)) 50 | this.insertPriority v iv 51 | queue.Enqueue iv v 52 | 53 | member this.boost (v:Var) = 54 | if not this.inTempMode then 55 | let p = this.getPriority v 56 | if (queue.Contains p v) then 57 | let newP = queue.Peek().Key - 1 58 | assert (newP > p) 59 | this.setPriority v newP 60 | let idx = queue.IndexOf p v 61 | queue.RemoveAt idx 62 | queue.Enqueue newP v 63 | 64 | member this.bump (v:Var) = 65 | if not this.inTempMode then 66 | let p = this.getPriority v 67 | let idx = queue.IndexOf p v 68 | if idx <> -1 then 69 | let newP = p - increment 70 | assert (newP < p) 71 | this.setPriority v newP 72 | 73 | queue.RemoveAt idx 74 | queue.Enqueue newP v 75 | 76 | member this.IsEmpty = queue.IsEmpty 77 | 78 | member this.suspend (v:Var) = 79 | if not this.inTempMode then 80 | let p = this.getPriority v // CMW: priority can stay in priorities.[v] 81 | let idx = queue.IndexOf p v 82 | if idx <> -1 then 83 | queue.RemoveAt idx 84 | 85 | member this.restore (v:Var) = 86 | if not this.inTempMode then 87 | let p = this.getPriority v 88 | assert (not (queue.Contains p v)) 89 | queue.Enqueue p v 90 | 91 | member this.next() = 92 | if not this.inTempMode then 93 | let mutable pair = queue.Dequeue() 94 | let p = pair.Key 95 | let v = pair.Value 96 | assert (p = this.getPriority v) 97 | this.setPriority v resetValue 98 | queue.Enqueue resetValue v // CMW: Is this necessary, or can we leave v unqueued? 99 | v 100 | else 101 | assert(false) 102 | -1 103 | 104 | end 105 | -------------------------------------------------------------------------------- /issues/gh1/gh1-2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (declare-fun a () (_ BitVec 8)) 4 | (declare-fun b () (_ BitVec 8)) 5 | (declare-fun c () (_ BitVec 8)) 6 | 7 | (assert (bvugt a #x0A)) 8 | (assert (bvugt b #x0A)) 9 | (assert (bvuge c #xF0)) 10 | 11 | (assert (= c (bvmul a b))) 12 | 13 | (check-sat) 14 | -------------------------------------------------------------------------------- /issues/gh1/gh1-simp.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (declare-fun a () (_ BitVec 8)) 4 | (declare-fun b () (_ BitVec 8)) 5 | ;;(declare-fun c () (_ BitVec 8)) 6 | 7 | (assert (bvugt a #x0A)) 8 | (assert (bvugt b #x0A)) 9 | ;;(assert (bvuge c #xF0)) 10 | ;;(assert (= c (bvmul a b))) 11 | 12 | (check-sat) 13 | ;; (get-model) 14 | -------------------------------------------------------------------------------- /issues/gh1/gh1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (declare-fun a () (_ BitVec 32)) 4 | (declare-fun b () (_ BitVec 32)) 5 | (declare-fun c () (_ BitVec 32)) 6 | 7 | (assert (bvugt a #x0000A000)) 8 | (assert (bvugt b #x0000A000)) 9 | (assert (bvuge c #xFFFFFFF0)) 10 | 11 | (assert (= c (bvmul a b))) 12 | 13 | (check-sat) 14 | -------------------------------------------------------------------------------- /mcBV-mono.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 2837972c-b670-49c5-8a63-a547c30652e4 9 | Exe 10 | mcBV 11 | mcBV 12 | v4.5 13 | true 14 | 4.3.1.0 15 | mcBV 16 | 17 | 18 | true 19 | full 20 | false 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | 3 25 | x86 26 | bin\Debug\mcBV.XML 27 | false 28 | ..\..\benchmarks\myTests\arithmetic.smt2 29 | 30 | 31 | pdbonly 32 | true 33 | true 34 | bin\Release\ 35 | TRACE 36 | 3 37 | AnyCPU 38 | bin\Release\mcBV.XML 39 | true 40 | C:\Users\aleks\Documents\GitHub\mcbv\mcBV\benchmarks\myTests\repeat.smt2 41 | 42 | 43 | 44 | packages\FSharp.Core.3.0.2\lib\net40\FSharp.Core.dll 45 | True 46 | 47 | 48 | z3-mono\Microsoft.Z3.dll 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 11 103 | 104 | 105 | true 106 | full 107 | false 108 | false 109 | bin\Debug\ 110 | DEBUG;TRACE 111 | 3 112 | bin\Debug\mcBV.XML 113 | true 114 | x86 115 | C:\git\mcbv\mcBV\benchmarks\myTests\test.smt2 116 | true 117 | 118 | 119 | pdbonly 120 | true 121 | true 122 | bin\Release\ 123 | TRACE 124 | 3 125 | bin\Release\mcBV.XML 126 | true 127 | x86 128 | 129 | 130 | 131 | 132 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 133 | 134 | 135 | 136 | 137 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 138 | 139 | 140 | 141 | 142 | 143 | cp $(ProjectDir)/z3-mono/libz3.so libz3.dll 144 | 145 | 152 | 153 | -------------------------------------------------------------------------------- /mcBV.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 2837972c-b670-49c5-8a63-a547c30652e4 9 | Exe 10 | mcBV 11 | mcBV 12 | v4.5 13 | true 14 | 4.3.1.0 15 | mcBV 16 | OnBuildSuccess 17 | 18 | 19 | true 20 | full 21 | false 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | 3 26 | x86 27 | bin\Debug\mcBV.XML 28 | false 29 | -I I:\mcbv\mcBV\benchmarks\myTests\explanation1.smt2 30 | true 31 | 32 | 33 | pdbonly 34 | true 35 | true 36 | bin\Release\ 37 | TRACE 38 | 3 39 | AnyCPU 40 | bin\Release\mcBV.XML 41 | true 42 | f:\smtlib-old\QF_BV\sage\app7\bench_3884.smt2 43 | true 44 | 45 | 46 | 11 47 | 48 | 49 | true 50 | full 51 | false 52 | false 53 | bin\Debug\ 54 | DEBUG;TRACE 55 | 3 56 | bin\Debug\mcBV.XML 57 | true 58 | x86 59 | -V -D -T -K -g bug3.smt2 60 | true 61 | 62 | 63 | pdbonly 64 | true 65 | true 66 | bin\Release\ 67 | TRACE 68 | 3 69 | bin\Release\mcBV.XML 70 | true 71 | x86 72 | toobad.smt2 73 | false 74 | 75 | 76 | 77 | 78 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 79 | 80 | 81 | 82 | 83 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll 141 | True 142 | 143 | 144 | z3\Microsoft.Z3.dll 145 | 146 | 147 | 148 | 149 | 150 | 151 | 158 | -------------------------------------------------------------------------------- /mcBV.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "mcBV", "mcBV.fsproj", "{2837972C-B670-49C5-8A63-A547C30652E4}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B38040C3-7AD9-4E58-A623-50D6E5D48A5E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x86 = Debug|x86 14 | Release|Any CPU = Release|Any CPU 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {2837972C-B670-49C5-8A63-A547C30652E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {2837972C-B670-49C5-8A63-A547C30652E4}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {2837972C-B670-49C5-8A63-A547C30652E4}.Debug|x86.ActiveCfg = Debug|x86 21 | {2837972C-B670-49C5-8A63-A547C30652E4}.Debug|x86.Build.0 = Debug|x86 22 | {2837972C-B670-49C5-8A63-A547C30652E4}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {2837972C-B670-49C5-8A63-A547C30652E4}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {2837972C-B670-49C5-8A63-A547C30652E4}.Release|x86.ActiveCfg = Release|x86 25 | {2837972C-B670-49C5-8A63-A547C30652E4}.Release|x86.Build.0 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/bogus_implication.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun X5 () (_ BitVec 1)) 5 | (declare-fun X2 () (_ BitVec 8)) 6 | (declare-fun X1 () (_ BitVec 64)) 7 | (declare-fun X3 () (_ BitVec 1)) 8 | (declare-fun X4 () (_ BitVec 1)) 9 | (declare-fun X7 () (_ BitVec 1)) 10 | (declare-fun X6 () (_ BitVec 1)) 11 | 12 | (assert (= X1 ((_ sign_extend 56) X2))) 13 | (assert (= (= X3 (_ bv1 1)) (distinct X1 ((_ extract 63 0) (_ bv0 64))))) 14 | (assert (= X4 (bvand X5 X3))) 15 | (assert (= (= X6 (_ bv1 1)) (=> (= X4 (_ bv1 1)) (= X7 (_ bv1 1))))) 16 | (assert (= (= (_ bv1 1) (_ bv1 1)) (= ((_ extract 0 0) (_ bv0 64)) X6))) 17 | (check-sat) 18 | 19 | -------------------------------------------------------------------------------- /tests/bogus_implication2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | (declare-fun X5 () (_ BitVec 1)) 4 | (declare-fun X2 () (_ BitVec 64)) 5 | (declare-fun X3 () (_ BitVec 1)) 6 | (declare-fun X4 () (_ BitVec 1)) 7 | (declare-fun X6 () (_ BitVec 1)) 8 | (declare-fun X7 () (_ BitVec 1)) 9 | 10 | (assert (= (= X3 (_ bv1 1)) (distinct X2 ((_ extract 63 0) (_ bv0 64))))) 11 | (assert (= X4 (bvand X5 X3))) 12 | (assert (= (= X7 (_ bv1 1)) (=> (= X4 (_ bv1 1)) (= X6 (_ bv1 1))))) 13 | (assert (= true (= ((_ extract 0 0) (_ bv0 64)) X7))) 14 | (check-sat) 15 | (exit) 16 | -------------------------------------------------------------------------------- /tests/boolprop.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (declare-fun var_100 () Bool) 4 | (declare-fun var_101 () Bool) 5 | (declare-fun var_102 () Bool) 6 | (declare-fun var_103 () Bool) 7 | (declare-fun var_104 () Bool) 8 | (declare-fun var_105 () Bool) 9 | (declare-fun var_106 () Bool) 10 | (declare-fun var_107 () Bool) 11 | (declare-fun w_1 () (_ BitVec 4)) 12 | (declare-fun w_2 () (_ BitVec 4)) 13 | (declare-fun w_3 () (_ BitVec 4)) 14 | (declare-fun w_4 () (_ BitVec 4)) 15 | (declare-fun w_5 () (_ BitVec 4)) 16 | (declare-fun w_6 () (_ BitVec 4)) 17 | (declare-fun w_7 () (_ BitVec 4)) 18 | (declare-fun var_108 () Bool) 19 | (declare-fun w_8 () (_ BitVec 4)) 20 | (declare-fun w_9 () (_ BitVec 4)) 21 | (declare-fun w_10 () (_ BitVec 4)) 22 | (declare-fun w_11 () (_ BitVec 4)) 23 | (declare-fun w_12 () (_ BitVec 4)) 24 | (declare-fun w_13 () (_ BitVec 4)) 25 | (declare-fun w_14 () (_ BitVec 4)) 26 | (declare-fun var_109 () Bool) 27 | (declare-fun var_110 () Bool) 28 | (declare-fun var_111 () Bool) 29 | (declare-fun var_112 () Bool) 30 | (declare-fun var_113 () Bool) 31 | (declare-fun var_114 () Bool) 32 | (declare-fun var_115 () Bool) 33 | (declare-fun var_116 () Bool) 34 | (declare-fun w_15 () (_ BitVec 4)) 35 | (declare-fun w_16 () (_ BitVec 4)) 36 | (declare-fun w_17 () (_ BitVec 4)) 37 | (declare-fun w_18 () (_ BitVec 4)) 38 | (declare-fun w_19 () (_ BitVec 4)) 39 | (declare-fun w_20 () (_ BitVec 4)) 40 | (declare-fun w_21 () (_ BitVec 4)) 41 | (declare-fun var_117 () Bool) 42 | (declare-fun w_22 () (_ BitVec 4)) 43 | (declare-fun w_23 () (_ BitVec 4)) 44 | (declare-fun w_24 () (_ BitVec 4)) 45 | (declare-fun w_25 () (_ BitVec 4)) 46 | (declare-fun w_26 () (_ BitVec 4)) 47 | (declare-fun w_27 () (_ BitVec 4)) 48 | (declare-fun w_28 () (_ BitVec 4)) 49 | 50 | 51 | (assert (and 52 | (= false (or (not var_107) var_108 var_117 (and var_115 var_106))) 53 | (=> var_102 (= (bvsub w_3 w_2) (_ bv1 4))) 54 | (=> (not var_102) (= w_3 w_2)) 55 | (=> var_103 (= (bvsub w_4 w_3) (_ bv1 4))) 56 | (=> (not var_103) (= w_4 w_3)) 57 | (=> (not var_104) (= w_5 w_4)) 58 | (=> (not var_105) (= w_6 w_5)) 59 | (=> (not var_106) (= w_7 w_6)) 60 | (= var_107 (bvuge w_7 (_ bv1 4))) 61 | (=> var_100 (= w_8 (_ bv1 4))) 62 | (=> (not var_100) (= w_8 (_ bv0 4))) 63 | (=> var_101 (= (bvsub w_9 w_8) (_ bv1 4))) 64 | (=> (not var_101) (= w_9 w_8)) 65 | (=> var_102 (= (bvsub w_10 w_9) (_ bv1 4))) 66 | (=> (not var_102) (= w_10 w_9)) 67 | (=> var_103 (= (bvsub w_11 w_10) (_ bv1 4))) 68 | (=> (not var_103) (= w_11 w_10)) 69 | (=> var_104 (= (bvsub w_12 w_11) (_ bv1 4))) 70 | (=> (not var_104) (= w_12 w_11)) 71 | 72 | (=> var_105 (= (bvsub w_13 w_12) (_ bv1 4))) 73 | (=> (not var_105) (= w_13 w_12)) 74 | (=> var_106 (= (bvsub w_14 w_13) (_ bv1 4))) 75 | (=> (not var_106) (= w_14 w_13)) 76 | (= var_108 (bvuge w_14 (_ bv2 4))) 77 | (=> var_112 (= (bvsub w_18 w_17) (_ bv1 4))) 78 | (=> (not var_112) (= w_18 w_17)) 79 | (=> var_113 (= (bvsub w_19 w_18) (_ bv1 4))) 80 | (=> (not var_113) (= w_19 w_18)) 81 | (=> var_114 (= (bvsub w_20 w_19) (_ bv1 4))) 82 | (=> (not var_114) (= w_20 w_19)) 83 | (=> var_115 (= (bvsub w_21 w_20) (_ bv1 4))) 84 | (=> (not var_115) (= w_21 w_20)) 85 | (=> var_109 (= w_22 (_ bv1 4))) 86 | (=> (not var_109) (= w_22 (_ bv0 4))) 87 | (=> var_110 (= (bvsub w_23 w_22) (_ bv1 4))) 88 | (=> (not var_110) (= w_23 w_22)) 89 | (=> var_111 (= (bvsub w_24 w_23) (_ bv1 4))) 90 | (=> (not var_111) (= w_24 w_23)) 91 | (=> var_112 (= (bvsub w_25 w_24) (_ bv1 4))) 92 | (=> (not var_112) (= w_25 w_24)) 93 | (=> (not var_113) (= w_26 w_25)) 94 | (=> var_114 (= (bvsub w_27 w_26) (_ bv1 4))) 95 | (=> (not var_114) (= w_27 w_26)) 96 | (=> var_115 (= (bvsub w_28 w_27) (_ bv1 4))) 97 | (=> (not var_115) (= w_28 w_27)) 98 | (= var_117 (bvuge w_28 (_ bv2 4))) 99 | )) 100 | (check-sat) 101 | -------------------------------------------------------------------------------- /tests/bvadd-unsat.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :source | 3 | Constructed by Aleksandar Zeljic 4 | |) 5 | (set-info :smt-lib-version 2.0) 6 | (set-info :category "check") 7 | (set-info :status unsat) 8 | (declare-fun a () (_ BitVec 4)) 9 | (declare-fun b () (_ BitVec 4)) 10 | (declare-fun c () (_ BitVec 4)) 11 | 12 | 13 | (assert (bvult b #b0101)) 14 | (assert (bvult a #b0011)) 15 | (assert (bvugt c #b1000)) 16 | (assert (= c (bvadd a b))) 17 | (check-sat) 18 | (exit) 19 | -------------------------------------------------------------------------------- /tests/bvadd.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :source | 3 | Constructed by Aleksandar Zeljic to test bvAdd 4 | |) 5 | (set-info :smt-lib-version 2.0) 6 | (set-info :category "check") 7 | (set-info :status sat) 8 | (declare-fun a () (_ BitVec 4)) 9 | (declare-fun b () (_ BitVec 4)) 10 | (declare-fun c () (_ BitVec 4)) 11 | 12 | 13 | (assert (bvule b #b0101)) 14 | (assert (bvule a #b0011)) 15 | (assert (bvuge c #b1000)) 16 | (assert (= c (bvadd a b))) 17 | (check-sat) 18 | (exit) 19 | -------------------------------------------------------------------------------- /tests/bvdiv.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :source | 3 | Constructed by Aleksandar Zeljic to test bvDiv 4 | |) 5 | (set-info :smt-lib-version 2.0) 6 | (set-info :category "check") 7 | (set-info :status sat) 8 | (declare-fun a () (_ BitVec 4)) 9 | (declare-fun b () (_ BitVec 4)) 10 | (declare-fun c () (_ BitVec 4)) 11 | 12 | (assert (bvule #b0010 b)) 13 | (assert (bvule b c)) 14 | (assert (= #b0000 (bvudiv #b0000 b))) 15 | (assert (= b (bvudiv b #b0001))) 16 | (assert (= a (bvudiv c b))) 17 | (assert (= c (bvmul a b))) 18 | 19 | (check-sat) 20 | (exit) 21 | -------------------------------------------------------------------------------- /tests/concat1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun Y () (_ BitVec 32)) 7 | 8 | (assert (and 9 | (not (= (bvand (bvshl (bvand ((_ zero_extend 24) X) (_ bv255 32)) ((_ zero_extend 24) (_ bv2 8))) (_ bv15 32)) (_ bv0 32))) 10 | (= Y (bvand (bvshl (bvand ((_ zero_extend 24) X) (_ bv255 32)) ((_ zero_extend 24) (_ bv2 8))) (_ bv15 32))) 11 | (not (= (bvsub Y (_ bv3 32)) (_ bv0 32))) 12 | (bvslt (_ bv0 32) (bvadd Y (_ bv115 32))) 13 | (not (= Y (_ bv4294967295 32))) 14 | )) 15 | 16 | (check-sat) 17 | ; (get-model) 18 | -------------------------------------------------------------------------------- /tests/concat2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun Y () (_ BitVec 32)) 7 | 8 | (declare-fun k!0 () (_ BitVec 2)) 9 | (declare-fun mcbv!1 () (_ BitVec 32)) 10 | (declare-fun mcbv!2 () (_ BitVec 32)) 11 | (declare-fun mcbv!3 () (_ BitVec 30)) 12 | (declare-fun mcbv!4 () (_ BitVec 32)) 13 | 14 | (assert (and 15 | (not (= k!0 #b00)) 16 | (= Y mcbv!1) 17 | (not (= Y #x00000003)) 18 | (bvule #x80000000 mcbv!2) 19 | (not (= Y #x7fffff8d)) 20 | (not (= Y #xffffffff)) 21 | (= mcbv!1 mcbv!4) 22 | (= mcbv!2 (bvadd #x80000072 Y)) 23 | (= mcbv!3 (concat #x0000000 k!0)) 24 | (= mcbv!4 (concat mcbv!3 #b00)) 25 | )) 26 | 27 | ;; Z3 says SAT w/ the following model: 28 | ;; 29 | ;; (model 30 | ;; (define-fun k!0 () (_ BitVec 2) 31 | ;; #b01) 32 | ;; (define-fun Y () (_ BitVec 32) 33 | ;; #x00000004) 34 | ;; (define-fun mcbv!3 () (_ BitVec 30) 35 | ;; #b000000000000000000000000000001) 36 | ;; (define-fun mcbv!2 () (_ BitVec 32) 37 | ;; #x80000076) 38 | ;; (define-fun mcbv!4 () (_ BitVec 32) 39 | ;; #x00000004) 40 | ;; (define-fun mcbv!1 () (_ BitVec 32) 41 | ;; #x00000004) 42 | ;; ) 43 | 44 | 45 | (check-sat) 46 | ; (get-model) 47 | -------------------------------------------------------------------------------- /tests/sdiv1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun v1 () (_ BitVec 4)) 5 | (declare-fun v3 () (_ BitVec 4)) 6 | (declare-fun v4 () (_ BitVec 4)) 7 | (declare-fun v5 () (_ BitVec 1)) 8 | 9 | (assert 10 | (= (ite 11 | (= (_ bv1 1) v5) 12 | (bvsdiv v1 v3) 13 | v4) 14 | v1) 15 | ) 16 | 17 | (check-sat) 18 | 19 | -------------------------------------------------------------------------------- /tests/sle1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | (declare-fun X () (_ BitVec 8)) 4 | (assert (bvsle ((_ zero_extend 3) X) (_ bv0 11))) 5 | (check-sat) 6 | 7 | -------------------------------------------------------------------------------- /tests/sle2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | (declare-fun X () (_ BitVec 3)) 4 | (assert (bvsle ((_ sign_extend 1) X) (_ bv0 4))) 5 | (check-sat) 6 | 7 | -------------------------------------------------------------------------------- /tests/sle3.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | (declare-fun X () (_ BitVec 4)) 4 | (assert (bvsle ((_ sign_extend 2) X) (_ bv0 6))) 5 | (check-sat) 6 | 7 | -------------------------------------------------------------------------------- /tests/slt1-unsat.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status unsat) 4 | 5 | (declare-const X (_ BitVec 4)) 6 | 7 | (assert (and 8 | (= X #x1) 9 | (bvslt X #xF))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-const X (_ BitVec 8)) 6 | 7 | (assert (and 8 | (= X #x01) 9 | (bvslt X #x0F))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt2-unsat.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status unsat) 4 | 5 | (declare-const X (_ BitVec 4)) 6 | 7 | (assert (and 8 | (not (bvslt X #x0)) 9 | (bvslt X #xF))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-const X (_ BitVec 8)) 6 | 7 | (assert (and 8 | (not (bvslt X #x00)) 9 | (bvslt X #x0F))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt3-unsat.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-const X (_ BitVec 4)) 6 | 7 | (assert (and 8 | (not (bvslt X #x1)) 9 | (bvslt X #x3))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt3.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-const X (_ BitVec 4)) 6 | 7 | (assert (and 8 | (not (bvslt X #x1)) 9 | (bvslt X #x3))) 10 | 11 | (check-sat) 12 | -------------------------------------------------------------------------------- /tests/slt4.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | (declare-fun X () (_ BitVec 16)) 4 | (assert (bvslt X (_ bv0 16))) 5 | (check-sat) 6 | -------------------------------------------------------------------------------- /tests/soundness1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun X5 () (_ BitVec 1)) 5 | (declare-fun X2 () (_ BitVec 8)) 6 | (declare-fun X1 () (_ BitVec 64)) 7 | (declare-fun X3 () (_ BitVec 1)) 8 | (declare-fun X4 () (_ BitVec 1)) 9 | (declare-fun X7 () (_ BitVec 1)) 10 | (declare-fun X6 () (_ BitVec 1)) 11 | 12 | (assert (= X1 ((_ sign_extend 56) X2))) 13 | (assert (= (= X3 (_ bv1 1)) (distinct X1 ((_ extract 63 0) (_ bv0 64))))) 14 | (assert (= X4 (bvand X5 X3))) 15 | (assert (= (= X6 (_ bv1 1)) (=> (= X4 (_ bv1 1)) (= X7 (_ bv1 1))))) 16 | (assert (= (= (_ bv1 1) (_ bv1 1)) (= ((_ extract 0 0) (_ bv0 64)) X6))) 17 | (check-sat) 18 | 19 | -------------------------------------------------------------------------------- /tests/udiv1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun v1 () (_ BitVec 8)) 5 | (declare-fun v3 () (_ BitVec 8)) 6 | (declare-fun v4 () (_ BitVec 8)) 7 | (declare-fun v5 () (_ BitVec 1)) 8 | 9 | (assert 10 | (not (= (ite 11 | true 12 | (bvudiv v1 v3) 13 | v4) 14 | v1)) 15 | ) 16 | 17 | (check-sat) 18 | 19 | -------------------------------------------------------------------------------- /tests/udiv2.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun v1 () (_ BitVec 32)) 5 | (declare-fun v3 () (_ BitVec 32)) 6 | (declare-fun v4 () (_ BitVec 32)) 7 | (declare-fun v5 () (_ BitVec 1)) 8 | 9 | (assert 10 | (= (ite 11 | (= (_ bv1 1) v5) 12 | (bvudiv v1 v3) 13 | v4) 14 | v1) 15 | ) 16 | 17 | (check-sat) 18 | 19 | -------------------------------------------------------------------------------- /tests/uge.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun mcbv!0 () (_ BitVec 8)) 7 | 8 | 9 | (assert (bvuge #x01 X)) 10 | 11 | ;; The above gets rewritten to: 12 | 13 | ;; (assert (bvule #x01 mcbv!0)) 14 | ;; (assert (not (= X #x00))) 15 | ;; (assert (= mcbv!0 (bvadd #xff X))) 16 | 17 | ;; 1:bv := Z3's mcbv!0 18 | ;; [2] := Z3's (bvule #x01 mcbv!0) 19 | ;; 3:bv := Z3's X 20 | ;; [4] := Z3's (= X #x00) 21 | ;; [5] := Z3's (= mcbv!0 (bvadd #xff X)) 22 | 23 | ;; Boolean watches: 24 | ;; | ==> 2 25 | ;; | ==> -4 26 | ;; | ==> 5 27 | 28 | 29 | (check-sat) 30 | ; (get-model) 31 | 32 | -------------------------------------------------------------------------------- /tests/ugt.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun mcbv!0 () (_ BitVec 8)) 7 | 8 | 9 | (assert (bvslt #x01 X)) 10 | 11 | ;; The above gets rewritten to: 12 | 13 | ;; (assert (bvule #x01 mcbv!0)) 14 | ;; (assert (not (= X #x00))) 15 | ;; (assert (= mcbv!0 (bvadd #xff X))) 16 | 17 | ;; 1:bv := Z3's mcbv!0 18 | ;; [2] := Z3's (bvule #x01 mcbv!0) 19 | ;; 3:bv := Z3's X 20 | ;; [4] := Z3's (= X #x00) 21 | ;; [5] := Z3's (= mcbv!0 (bvadd #xff X)) 22 | 23 | ;; Boolean watches: 24 | ;; | ==> 2 25 | ;; | ==> -4 26 | ;; | ==> 5 27 | 28 | 29 | (check-sat) 30 | ; (get-model) 31 | 32 | -------------------------------------------------------------------------------- /tests/ule.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun mcbv!0 () (_ BitVec 8)) 7 | 8 | 9 | (assert (bvult #x01 X)) 10 | 11 | ;; The above gets rewritten to: 12 | 13 | ;; (assert (bvule #x01 mcbv!0)) 14 | ;; (assert (not (= X #x00))) 15 | ;; (assert (= mcbv!0 (bvadd #xff X))) 16 | 17 | ;; 1:bv := Z3's mcbv!0 18 | ;; [2] := Z3's (bvule #x01 mcbv!0) 19 | ;; 3:bv := Z3's X 20 | ;; [4] := Z3's (= X #x00) 21 | ;; [5] := Z3's (= mcbv!0 (bvadd #xff X)) 22 | 23 | ;; Boolean watches: 24 | ;; | ==> 2 25 | ;; | ==> -4 26 | ;; | ==> 5 27 | 28 | 29 | (check-sat) 30 | ; (get-model) 31 | 32 | -------------------------------------------------------------------------------- /tests/ule1.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | (set-info :status sat) 3 | 4 | (declare-fun X () (_ BitVec 4)) 5 | 6 | (assert (bvule #b100000 ((_ sign_extend 2) X))) 7 | ;; sat e.g., when (= X #x8) 8 | 9 | (check-sat) 10 | -------------------------------------------------------------------------------- /tests/ult.smt2: -------------------------------------------------------------------------------- 1 | (set-logic QF_BV) 2 | 3 | (set-info :status sat) 4 | 5 | (declare-fun X () (_ BitVec 8)) 6 | (declare-fun mcbv!0 () (_ BitVec 8)) 7 | 8 | 9 | (assert (bvugt #x01 X)) 10 | 11 | ;; The above gets rewritten to: 12 | 13 | ;; (assert (bvule #x01 mcbv!0)) 14 | ;; (assert (not (= X #x00))) 15 | ;; (assert (= mcbv!0 (bvadd #xff X))) 16 | 17 | ;; 1:bv := Z3's mcbv!0 18 | ;; [2] := Z3's (bvule #x01 mcbv!0) 19 | ;; 3:bv := Z3's X 20 | ;; [4] := Z3's (= X #x00) 21 | ;; [5] := Z3's (= mcbv!0 (bvadd #xff X)) 22 | 23 | ;; Boolean watches: 24 | ;; | ==> 2 25 | ;; | ==> -4 26 | ;; | ==> 5 27 | 28 | 29 | (check-sat) 30 | ; (get-model) 31 | 32 | -------------------------------------------------------------------------------- /z3-mono/README.md: -------------------------------------------------------------------------------- 1 | mcBV requires [Z3](http://github.com/Z3Prover/Z3). If you are building with mono on Linux, libz3.so and Microsoft.Z3.dll should be put into this directory. -------------------------------------------------------------------------------- /z3/README.md: -------------------------------------------------------------------------------- 1 | mcBV requires [Z3](http://github.com/Z3Prover/Z3); specifically, libz3.dll and Microsoft.Z3.dll should be put into this directory. --------------------------------------------------------------------------------