I want to find the weakest precondition given an action and post condition using z3py.
Given the action N = N + 1 and the post condition N == 5 the weakest precondition would be N == 4.
Using the Tactic solve-eqs this approach works for some post conditions but not others.
When using the post condition N < 5 I get [[Not(4 <= N)]].
But when using N == 5 I get [[]], when I would like N == 4.
N2 = Int('N2') # N after the action
N = Int('N') # N before the action
weakestPreconditionGoal = Goal()
# 'N2 == n + 1' action
# 'N2 == 5' post condition.
weakestPreconditionGoal.add(N2 == N + 1, N2 == 5)
t = Tactic('solve-eqs')
wp = t(weakestPreconditionGoal)
print(wp)
Is this the best approach find the weakest precondition?
I have tried a several methods but am new to Z3 and can not figure out what approach to take or how to implement it.
Yes, solve-eqs can be used to eliminate equalities. The problem is that we have no control over which equalities will be eliminated. Another option is to use qe (quantifier elimination). The example is also available here.
N2 = Int('N2') # N after the action
N = Int('N') # N before the action
weakestPreconditionGoal = Goal()
# 'N2 == n + 1' action
# 'N2 == 5' post condition.
weakestPreconditionGoal.add(Exists([N2], And(N2 == N + 1, N2 == 5)))
t = Tactic('qe')
wp = t(weakestPreconditionGoal)
print(wp)
Another option is to use solve-eqs, but "guard" equations that we don't want to eliminate.
We can guard the equations by using an auxiliary predicate guard. Here is an example (also available online here). Of course, we will have to perform a second pass to eliminate guard from the result.
N2 = Int('N2') # N after the action
N = Int('N') # N before the action
guard = Function('guard', BoolSort(), BoolSort())
weakestPreconditionGoal = Goal()
# 'N2 == n + 1' action
# 'N2 == 5' post condition.
weakestPreconditionGoal.add(N2 == N + 1, guard(N2 == 5))
t = Tactic('solve-eqs')
wp = t(weakestPreconditionGoal)
print(wp)
Related
I want to solve a CSP with the help of Lookahead method in z3 Solver. The issue I'm facing is not being convinced that it's invoked by setting an according parameter like s.set("sat.lookahead_simplify", True) or s.set("sat.lookahead.delta_fraction", 0.7).
Below is the code for solving my combinatorial problem. I ren a similar solver on a complex instance A and the runtime without these settings on Lookahead was 3674 seconds versus 3670 secunds with these settings. So, seems like they have no effect.
Does anyone know how to correctly invoke Lookahead here?
import numpy as np
import timeit
from z3 import *
def as_long(self):
if z3_debug():
_z3_assert(self.is_int(), "Integer value expected")
return int(self.as_string())
def model_int(mo, R, C, m, n):
R_int = [mo[R[i]].as_long() for i in range(m)]
C_int = [mo[C[j]].as_long() for j in range(n)]
return [R_int, C_int] # integer model values
def CSP(A, D, bit_length=8):
A_shape = A.shape
m = A_shape[0]
n = A_shape[1]
#initialize solver
s = Solver()
s.set("lookahead_simplify", True)
s.set("sat.lookahead.delta_fraction", 0.7)
#initialize column and row variables c_j and r_i as bit vectors
C = [BitVec(f"c_{j + 1}", bit_length) for j in range(n)]
R = [BitVec(f"r_{i + 1}", bit_length) for i in range(m)]
#initialize search space restriction constraints for r_i's as lists
Constr_D = [Or([r == d for d in D]) for r in R]
#initialize permit-constraints as lists
Constr_permit = [R[i] & C[j] == C[j] for i in range(m) for j in range(n) if A[i,j]]
Constr_npermit = [R[i] & C[j] != C[j] for i in range(m) for j in range(n) if not A[i,j]]
#add constraints
s.add(Constr_D + Constr_permit + Constr_npermit)
#search solution
check = s.check()
if check == sat:
return model_int(s.model(), R, C, m, n)
return check
# model instance ........
D = [7,11,19,35,67,13,21,37,69,25,41,73,49,81,82,84,88] #domain
m = 15 #number of rows
n = 9 #number of columns
p=.11
A = np.random.choice(a=[1,0],size=(m,n),p=[p,1-p])
print(A)
# executing solver on model instance ........
starttime = timeit.default_timer()
print(CSP(A,D))
print("The time difference is :", timeit.default_timer() - starttime)
I'm experimenting with (and failing at) reducing sets in z3 over operations like addition. The idea is eventually to prove stuff about arbitrary reductions over reasonably-sized fixed-sized sets.
The first of the two examples below seems like it should yield unsat, but it doesn't. The second does work, but I would prefer not to use it as it requires incrementally fiddling with the model.
def test_reduce():
LIM = 5
VARS = 10
poss = [Int('i%d'%x) for x in range(VARS)]
i = Int('i')
s = Solver()
arr = Array('arr', IntSort(), BoolSort())
s.add(arr == Lambda(i, And(i < LIM, i >= 0)))
a = arr
for x in range(len(poss)):
s.add(Implies(a != EmptySet(IntSort()), arr[poss[x]]))
a = SetDel(a, poss[x])
def final_stmt(l):
if len(l) == 0: return 0
return If(Not(arr[l[0]]), 0, l[0] + (0 if len(l) == 1 else final_stmt(l[1:])))
sm = final_stmt(poss)
s.push()
s.add(sm == 1)
assert s.check() == unsat
Interestingly, the example below works much better, but I'm not sure why...
def test_reduce_with_loop_model():
s = Solver()
i = Int('i')
arr = Array('arr', IntSort(), BoolSort())
LIM = 1000
s.add(arr == Lambda(i, And(i < LIM, i >= 0)))
sm = 0
f = Int(str(uuid4()))
while True:
s.push()
s.add(arr[f])
chk = s.check()
if chk == unsat:
s.pop()
break
tmp = s.model()[f]
sm = sm + tmp
s.pop()
s.add(f != tmp)
s.push()
s.add(sm == sum(range(LIM)))
assert s.check() == sat
s.pop()
s.push()
s.add(sm == 11)
assert s.check() == unsat
Note that your call to:
f = Int(str(uuid4()))
Is inside the loop in the first case, and is outside the loop in the second case. So, the second case simply works on one variable, and thus converges quickly. While the first one keeps creating variables and creates a much harder problem for z3. It's not surprising at all that these two behave significantly differently, as they encode entirely different constraints.
As a general note, reducing an array of elements with an operation is just not going to be an easy problem for z3. First, you have to assume an upper bound on the elements. And if that's the case, then why bother with Lambda or Array at all? Simply create a Python list of that many variables, and ignore the array logic completely. That is:
elts = [Int("s%d"%i) for i in range(100)]
And then to access the elements of your 'array', simply use Python accessor notation elts[12].
Note that this only works if all your accesses are with a constant integer; i.e., your index cannot be symbolic. But if you're looking for proving reduction properties, that should suffice; and would be much more efficient.
Right now I have this Ruby method that returns 3 different numbers:
# Find integers s and t such that gcd(a,b) = s*a + t*b
# pre: a,b >= 0
# post: return gcd(a,b), s, t
def egcd(a, b)
# let A, B = a, b
s, t, u, v = 1, 0, 0, 1
while 0 < b
# loop invariant: a = sA + tB and b = uA + vB and gcd(a,b) = gcd(A,B)
q = a / b
a, b, s, t, u, v = b, (a%b), u, v, (s-u*q), (t-v*q)
end
[a, s, t]
end
I want to only check the first return value, a.
if egcd(ARGV[3].to_i, 128) != 1
So this statement here does not work since it's returning 3 values, I just want to check if the first value is != 1. I'm fairly new to Ruby, does anyone know of a way to accomplish this? Thanks in advance!
Getting the first value of an array can be done in a few ways:
if egcd(ARGV[3].to_i, 128).first != 1
or
if egcd(ARGV[3].to_i, 128)[0] != 1
If you're only using the first value, I'd suggest re-writing your program to be a little more intuitive. I'd also consider re-writing this piece of code entirely as it doesn't read nicely at all.
Since your return value is an array, check to see if the first value of the array is not 1.
if egcd(ARGV[3].to_i, 128).first != 1
or
unless egcd(ARGV[3].to_i, 128).first == 1
You can do it this way:
if egcd(ARGV[3].to_i, 128)[0] != 1
...since the return is actually an array.
I am very new to z3py.
I am trying to code the following 2 expressions in z3py
and
More information on the problem can be found here
I did search stackoverflow a lot and came across a similar question
But unfortunately I could not get a satisfactory enough answer.
I tried coding the first one in SMT, in following way:
#InputGroup, BlockGroup, OutputGroup contain some integer values to represent blocks
InputGroup = [0,1,2]
BlockGroup = [2,3,4,5,6]
OutputGroup = [7,8,9]
Groups = [InputGroup, BlockGroup, OutputGroup]
NumberOfTasks = len(InputGroup)+ len(BlockGroup)+ len(OutputGroup)
M = Function('M', Intsort(), Intsort())
Task = Function('Task', Intsort(), Intsort(), Intsort())
summation1 = Int('summation1')
# each group from the Groups is represented by its index number
for r, g in enumerate(Groups):
for m in range(0, NumberOfTasks):
if(m in g):
s.add(summation1 == summation1+ M(Task(r,m)))
and the second expression in SMT the following way:
NumberOfInputs = len(InputGroup)
NumberOfBlocks = len(BlockGroup)
NumberOfOutputs = len(OutputGroup)
Node = Function('Node', Intsort(), Intsort(), Intsort())
f = Function('f', Intsort(), Intsort(), Intsort())
for r, g in enumerate(Groups):
if(r != Groups.index(InputGroup) and r != Groups.index(OutputGroup)):
for i in range(0,(NumberOfInputs+NumberOfBlocks+NumberOfOutputs)):
summation2 = Int('summation2')
for m in range(0, (NumberOfTasks)):
if(m in g and i in g):
s.add(summation2 == summation2+ f(Node(r,i), Task(r,m)))
s.add(summation2 == 1)
Although I get satisfactory result from the above equations, the model I get from it is kind of questionable.
I just want to know if I am representing this correctly or not.
I think you want to change:
# each group from the Groups is represented by its index number
for r, g in enumerate(Groups):
for m in range(0, NumberOfTasks):
if(m in g):
s.add(summation1 == summation1+ M(Task(r,m)))
to something like this:
# each group from the Groups is represented by its index number
sumTerms = [M(Task(r,m))
for r, g in enumerate(Groups):
for m in range(0, NumberOfTasks):
if(m in g)]
s.add(summation1 == Sum(sumTerms))
and similarly for the second example.
I am working on a client's site, and I'm writing an amortization schedule calculator in in ruby on rails. For longer loan term calculations, it doesn't seem to be breaking when the balance reaches 0
Here is my code:
def calculate_amortization_results
p = params[:price].to_i
i = params[:rate].to_d
l = params[:term].to_i
j = i/(12*100)
n = l * 12
m = p * (j / (1 - (1 + j) ** (-1 * n)))
#loanAmount = p
#rateAmount = i
#monthlyAmount = m
#amort = []
#interestAmount = 0
while p > 0
line = Hash.new
h = p*j
c = m-h
p = p-c
line["interest"] = h
line["principal"] = c
if p <= 0
line["balance"] = 0
else
line["balance"] = p
end
line["payment"] = h+c
#amort.push(line)
#interestAmount += h
end
end
And here is the view:
- #amort.each_with_index do |a, i|
%li
.m
= i+1
.i
= number_to_currency(a["interest"], :unit => "$")
.p
= number_to_currency(a["principal"], :unit => "$")
.pp
= number_to_currency(a["payment"], :unit => "$")
.b
= number_to_currency(a["balance"], :unit => "$")
What I am seeing is, in place of $0.00 in the final payment balance, it shows "-$-inf", iterates one more loop, then displays $0.00, but shows "-$-inf" for interest. It should loop until p gets to 0, then stop and set the balance as 0, but it isn't. Any idea what I've done wrong?
The calculator is here. It seems to work fine for shorter terms, like 5 years, but longer terms cause the above error.
Edit:
Changing the while loop to n.times do
and then changing the balance view to
= number_to_currency(a["balance"], :unit => "$", :negative_format => "$0.00")
Is a workaround, but i'd like to know why the while loop wouldn't work correctly
in Ruby the default for numerical values is Fixnum ... e.g.:
> 15 / 4
=> 3
You will see weird rounding errors if you try to use Fixnum values and divide them.
To make sure that you use Floats, at least one of the numbers in the calculation needs to be a Float
> 15.0 / 4
=> 3.75
> 15 / 4.0
=> 3.75
You do two comparisons against 0 , which should be OK if you make sure that p is a Float.
As the other answer suggests, you should use "decimal" type in your database to represent currency.
Please try if this will work:
def calculate_amortization_results
p = params[:price].to_f # instead of to_i
i = params[:rate].to_f # <-- what is to_d ? use to_f
l = params[:term].to_i
j = i/(12*100.0) # instead of 100
n = l * 12
m = p * (j / (1 - (1 + j) ** (-1 * n))) # division by zero if i==0 ==> j==0
#loanAmount = p
#rateAmount = i
#monthlyAmount = m
#amort = []
#interestAmount = 0.0 # instead of 0
while p > 0
line = Hash.new
h = p*j
c = m-h
p = p-c
line["interest"] = h
line["principal"] = c
if p <= 0
line["balance"] = 0
else
line["balance"] = p
end
line["payment"] = h+c
#amort.push(line)
#interestAmount += h
end
end
If you see "inf" in your output, you are doing a division by zero somewhere.. better check the logic of your calculation, and guard against division by zero.
according to Wikipedia the formula is:
http://en.wikipedia.org/wiki/Amortization_calculator
to improve rounding errors, it's probably better to re-structure the formula like this:
m = (p * j) / (1 - (1 + j) ** (-1 * n) # these are two divisions! x**-1 == 1/x
which is equal to:
m = (p * j) + (p * j) / ((1 + j) ** n) - 1.0)
which is equal to: (use this one)
q = p * j # this is much larger than 1 , so fewer rounding errors when dividing it by something
m = q + q / ((1 + j) ** n) - 1.0) # only one division
I think it has something to do with the floating point operations precision. It has already been discussed here: Ruby number precision with simple arithmetic and it would be better to use decimal format for financial purposes.
The answer could be computing the numbers in the loop, but with precomputed number of iterations and from the scratch.