├── .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.
--------------------------------------------------------------------------------