I have come across some unusual runtime behaviour in z3, and I wanted to ask why it is happening:
Example 1:
(set-info :smt-lib-version 2.6)
(set-info :status unknown)
(define-sort FPN () (Float32))
(declare-const a1 FPN)
(assert (fp.eq a1 ((_ to_fp 8 24) RNE 1)))
(declare-const a2 FPN)
(assert (fp.eq a2 ((_ to_fp 8 24) RNE -1)))
(declare-const a3 FPN)
(assert (fp.eq a3 ((_ to_fp 8 24) RNE 0.5)))
(define-fun afun ((x FPN) (a1Param FPN) (a2Param FPN) (a3Param FPN)) FPN (fp.mul RNE (fp.add RNE (fp.mul RNE a1Param x) a2Param) a3Param ))
(assert
(forall ((x0 FPN)) (not (fp.geq (afun x0 a1 a2 a3) x0)))
)
(check-sat)
(get-model)
(exit)
Example 2:
(set-info :smt-lib-version 2.6)
(set-info :status unknown)
(define-sort FPN () (Float32))
(declare-const a1 FPN)
(assert (fp.eq a1 ((_ to_fp 8 24) RNE 1)))
(declare-const a2 FPN)
(assert (fp.eq a2 ((_ to_fp 8 24) RNE -1)))
(declare-const a3 FPN)
(assert (fp.eq a3 ((_ to_fp 8 24) RNE 0.5)))
(define-fun afun ((x FPN)) FPN (fp.mul RNE (fp.add RNE (fp.mul RNE a1 x) a2) a3 ))
(assert
(forall ((x0 FPN)) (not (fp.geq (afun x0) x0)))
)
(check-sat)
(get-model)
(exit)
Example 1 has a runtime of ~0.26s, Example 2 has a runtime of ~0.35s, despite the only difference being that in function afun I am either calling the constants directly or passing them as parameters.
I have additionally noticed that sometimes the opposite happens (calling a constant directly being faster than passing it as a parameter).
I can't figure out why this is happening, so I wanted to ask here.
Thanks so much for any responses!
These problems get rewritten into Boolean logic and fp.mul is simply hard to analyze, just like multiplication in many other theories. You're basically at the mercy of the SAT solver, which uses various kinds of heuristics to solve many problems quickly, but on any given problem, it's not easy to predict it's behavior. It's very common for tiny changes to the input to result in huge changes in solving time. You can run Z3 with -v:10 to see which tactics get applied and to see some of the statistics from the SAT solver.
Related
Since I need to generate source-level CFG, I used CFG::buildCFG from libclang and can get the following example output:
[B0 (EXIT)]
Preds (2): B1 B2
[B1]
1: n->l->x = n->x
2: traverse(n->l)
3: traverse(n->r)
4: return;
Preds (1): B3
Succs (1): B0
[B2]
1: return;
Preds (1): B3
Succs (1): B0
[B3]
T: if <null expr>
Preds (1): B4
Succs (2): B2 B1
[B4 (ENTRY)]
Succs (1): B3
But I cannot use opt to generate dot file for visible CFG.
So, how can I convert the aforementioned output to visible CFG (i.e., dot file)?
I am trying a query list comprehension:
> (set xs '(1 2 3 4 5 6 7 8))
> (lc ((<- x xs) (when (> x 5))) x)
But I am getting the error exception error: undefined function when/1.
Is it possible to apply guard statements to lc?
According to the LFE User Guide, within a list comprehension qualifier, the guard must precede the list expression:
(<- pat {{guard}} list-expr)
This means your example should be written as follows:
lfe> (set xs '(1 2 3 4 5 6 7 8))
(1 2 3 4 5 6 7 8)
lfe> (lc ((<- x (when (> x 5)) xs)) x)
(6 7 8)
You could alternatively treat the greater-than expression as a normal boolean expression qualifier:
lfe> (lc ((<- x xs) (> x 5)) x)
(6 7 8)
So I created a basic Z3 spec to guide me in buying some specific retail products. So far all it can do is arbitrarily tell me what to buy without exceeding my available funds:
(declare-datatypes () ((Retailer FooMart BazTrading)))
(declare-datatypes () ((Cartridge .223Rem .7.62x39mm)))
(declare-datatypes () ((Casing Brass Steel)))
(declare-datatypes () ((Offer (Offer
(getRetailer Retailer)
(getCartridge Cartridge)
(getRounds Int) ; # of rounds
(getPrice Int) ; price in cents
(getCasing Casing)
(getQuantityAvail Int)
))))
(declare-const x1 Offer)
(declare-const x2 Offer)
(declare-const x3 Offer)
(declare-const x4 Offer)
(declare-const x5 Offer)
(assert (= x1 (Offer FooMart .223Rem 1000 17000 Steel 50)))
(assert (= x2 (Offer BazTrading .223Rem 500 13000 Brass 10)))
(assert (= x3 (Offer FooMart .7.62x39mm 1000 18000 Steel 15)))
(assert (= x4 (Offer BazTrading .7.62x39mm 100 1850 Steel 20)))
(assert (= x5 (Offer BazTrading .7.62x39mm 20 190 Steel 20)))
; the quantity purchased of each offer/product will be
; between 0 and the max quantity of the offer
(declare-const x1Qty Int)
(assert (>= x1Qty 0))
(assert (<= x1Qty (getQuantityAvail x1)))
(declare-const x2Qty Int)
(assert (>= x2Qty 0))
(assert (<= x2Qty (getQuantityAvail x2)))
(declare-const x3Qty Int)
(assert (>= x3Qty 0))
(assert (<= x3Qty (getQuantityAvail x3)))
(declare-const x4Qty Int)
(assert (>= x4Qty 0))
(assert (<= x4Qty (getQuantityAvail x4)))
(declare-const x5Qty Int)
(assert (>= x5Qty 0))
(assert (<= x5Qty (getQuantityAvail x5)))
; let's say i've got $500 to spend
(declare-const moneyToSpend Int)
(assert (= moneyToSpend 50000))
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (* x1Qty (getPrice x1))
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5)))
))
(assert (< amountSpent moneyToSpend))
(maximize amountSpent)
(check-sat)
(get-model)
https://rise4fun.com/Z3/WxQNw
At this point what I'd like to do is add additional assertions for when I only want to buy Brass cased cartridges, or if I only need a specific type of cartridge like .223Rem, or add in shipping calculations for each Retailer plus a $/round calculation with minimize constraint so that I'm not wasting money on shipping, or taking into account volume pricing discounts that certain Offers have (e.g. buy 5 or more, save $0.10/ea, buy 10 or more, save $0.15/ea).
The problem I have is that I feel like the solutions I came up with for these are repetitious and not very elegant and I feel like I'm missing something... particularly since it seems like I'm carrying a lot of overhead myself tracking the relationship between each xQty and the Offer it corresponds to.
For example, a solution to filtering on only Brass casings could be like this:
; non-Brass casings get set to qty 0
(assert (if (= (getCasing x1) Brass)
(>= x1Qty 0)
(= x1Qty 0)))
(assert (if (= (getCasing x2) Brass)
(>= x2Qty 0)
(= x2Qty 0)))
; ... etc.
Maybe a better example would be trying to implement volume discounts. Say if I wanted to capture volume discounts for offer x1:
; at this point i'm hardcoding prices in a bag-on-the-side
; function instead of in the x1 Offer itself :/
(define-fun x1Pricing ((qty Int)) Int
(if (>= 10 qty)
(* qty 16500)
(if (>= 5 qty)
(* qty 16800)
(* qty (getPrice x1))))
)
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (x1Pricing x1Qty)
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5)))
))
(assert (< amountSpent moneyToSpend))
It just feels like things are very disparate and I'm wondering if they need to be. Like is there a way for x1Pricing to be part of the Offer data type, and if so is that even a good way to do it?
My instinct is also to be putting things in lists and mapping over them or something; but while I see z3 has a native List implementation I couldn't grok how to use it or if it would be appropriate (writing asserts using select with specific index numbers seemed just as cumbersome as having totally separate constants).
So my question is, is there a more optimal way to be doing what I'm trying to do?
From some Z3Py examples I've seen it appears I could reduce some repetition by using Python list comprehensions and correlating things based on index, but I'm also wondering if I'm missing the big picture here with the direction I'm going. Thank you.
edit: I've added a very dumb/naive shipping cost calculation method and cost per round calculation:
(declare-const shippingCost Int)
(assert (= shippingCost
; FooMart charges a flat $75 shipping fee
(+ (if (or (= (getRetailer x1) FooMart)
(= (getRetailer x2) FooMart)
(= (getRetailer x3) FooMart)
(= (getRetailer x4) FooMart)
(= (getRetailer x5) FooMart))
7500
0
)
; BazTrading charges a flat $20 + $5 per 100 rounds
(if (or (= (getRetailer x1) BazTrading)
(= (getRetailer x2) BazTrading)
(= (getRetailer x3) BazTrading)
(= (getRetailer x4) BazTrading)
(= (getRetailer x5) BazTrading))
2000
0
)
(* (/ (+ (if (= (getRetailer x1) BazTrading)
(getRounds x1)
0)
(if (= (getRetailer x2) BazTrading)
(getRounds x2)
0)
(if (= (getRetailer x3) BazTrading)
(getRounds x3)
0)
(if (= (getRetailer x4) BazTrading)
(getRounds x4)
0)
(if (= (getRetailer x5) BazTrading)
(getRounds x5)
0))
100)
500)
)
))
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (x1Pricing x1Qty)
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5))
shippingCost)))
(assert (< amountSpent moneyToSpend))
(declare-const totalRounds Int)
(assert (= totalRounds
(+ (* x1Qty (getRounds x1))
(* x2Qty (getRounds x2))
(* x3Qty (getRounds x3))
(* x4Qty (getRounds x4))
(* x5Qty (getRounds x5)))
))
(declare-const amountSpentPerRound Real)
(assert (= amountSpentPerRound
(div amountSpent totalRounds)
))
(assert (> amountSpent 20000))
(assert (< amountSpent 30000))
(minimize amountSpentPerRound)
https://rise4fun.com/Z3/vEpa3
(Note the model is not satisfiable in the rise4fun online editor but works fine on my local machine using the latest Z3 source)
Now I really think I'm doing something wrong as shippingCost is always 12600. When I fiddle with the amountSpent max and min value assertions to try to push it into using only BazTrading or FooMart Offers (to bring shipping cost down), it hangs for several minutes before I kill it. 🤔
SMTLib is not good for writing such specifications. It should be treated more as an "assembly" language, and should be generated from other tools. This is where the high-level APIs come in, depending on your language of choice. There are high-level bindings from C, C++, Java, Python, Haskell, Scala.. You essentially should use those APIs to generate the constraints and use z3 via the API. Each binding has its own advantages/disadvantages, so I'd recommend starting with whatever host language you are most familiar with and use that.
This may be super simple but I cannot find a way to get Maxima to tell me that c is now 8, not 3? Can anyone help?
(%i1) a:1;
(%o1) 1
(%i2) b:2;
(%o2) 2
(%i3) c:a+b;
(%o3) 3
(%i4) ''c;
(%o4) 3
(%i5) a:6;
(%o5) 6
(%i6) ''c;
(%o6) 3
Many thanks
Tom
The easiest way is to define include a prevent evaluation (') operator in the definition ofc. For example:
(%i1) c : '(a+b);
(%o1) b + a
(%i2) a:1;
(%o2) 1
(%i3) b:2;
(%o3) 2
(%i4) ''c;
(%o4) 3
(%i5) a:6;
(%o5) 6
(%i6) ''c;
(%o6) 8
Note that you can also post-fix the values of a and b:
(%i7) c, a:11, b:5;
(%o7) 16
I'm currently starting a new language (PROLOG) and I came across with a few issues.
I'm developing a simple board game in which I'm required to print the board. I've developed a PrintBoard and initialBoard predicate (as shown below), and I want to be able to run it from the main predicate, just like so:
printBoard([Head|Tail]) :-
printRow(Head),
printBoard(Tail).
printBoard([]).
printRow([Head|Tail]) :-
write(Head),
write(' '),
printRow(Tail).
printRow([]) :- nl.
initialBoard(Board) :- Board = ([
['b0','b0','b0','b0','b1'],
['b0','b0','b0','b0','b0'],
['b0','b0','b0','b0','b0'],
['b0','b0','b0','b0','b0'],
['b2','b0','b0','b0','b0']
]).
main :- Board = initialBoard(Board), printBoard(Board).
By typing main. in the SICStus PROLOG, the program should output the following:
b0 b0 b0 b0 b1
b0 b0 b0 b0 b0
b0 b0 b0 b0 b0
b0 b0 b0 b0 b0
b2 b0 b0 b0 b0
But, instead, it returns nothing. (Returns no).
The only way it seems to work is by inserting the whole list all over again as the variable, just like so:
main :- printBoard(<insert whole list here>).
Even though I'm looking to run it as:
main :- printBoard(initialBoard(Board)).
The portion of code above works, if main is passed the Board argument, but is it possible without passing it?
Functional code:
main(Board) :- printBoard(initialBoard(Board)).