Learning Z3py - Is there support for arrays and loops - python

I'm going through Z3py and have a question with how to use the API in a couple specific cases. The code below is a simplified version of something I would ultimately like to use Z3 for. Some of my questions are:
1. Is there a way to create an arbitrarily long array of values like the variable 'a' below?
2. Can you access each element of the array in loops through Z3py?
3. Is it possible to assign a result back into an original variable or is a new variable needed? Will the conversion to CNF automatically add a unique id? (ie a += b)
Overall, I'm lost on how to apply the Z3py API for something like the below algorithm where the solution depends on 'b'. Any help or hints is/are appreciated, thank you.
import sys
import struct
a = "\xff\x33\x01\x88\x02\x11\x03\x55"
b = sys.stdin.read(1) #a byte of user input - value 'a' is good
c = ''
d = ''
for x in range(len(a)):
c += struct.pack( 'B', int(a[x].encode('hex'), 16)^int(b.encode('hex'), 16) )
print c.encode('hex')
second = '\x23\x23'
x = 0
while x < len(c):
d += struct.pack( 'h', int(c[x:x+1].encode('hex'), 16)^int(second.encode('hex'), 16) )
x += 2
print d.encode('hex')
if d == '\xbd\x23\x43\x23\x40\x23\x41\x23':
print "Good"
else:
print "Bad"

We can accomplish that by writing a Python program that produces a Z3 expression. We use Python loops and lists (we can also use arrays) in this program, but these lists contain Z3 "symbolic" expressions instead of Python values. The resultant list d is a list of Z3 expressions containing b. Then, we ask Z3 to find a b such that elements of d are "equal" to the characters in the string '\xbd\x23\x43\x23\x40\x23\x41\x23'. Here is the code:
from z3 import *
def str2array(a):
"""
Convert a string into a list of Z3 bit-vector values of size 8
"""
return [ BitVecVal(int(a[x].encode('hex'), 16), 8) for x in range(len(a)) ]
a = str2array("\xff\x33\x01\x88\x02\x11\x03\x55")
# 'a' is a list of Z3 bitvector constants.
print "a:", a
# The elements of 'a' may look like Python integers but they are Z3 expressions.
# We can use the method sexpr() to get these values in SMT 2.0 syntax.
print [ a_i.sexpr() for a_i in a ]
# b is a Z3 symbolic variable.
b = BitVec('b', 8)
# We compute a list 'c' of Z3 expressions from 'a' and 'b'.
# We use Python list comprehensions but we can also use a for-loop.
c = [ a_i ^ b for a_i in a ]
print "c:", c
second = '\x23\x23'
# We convert 'second' in a Z3 bit-vector value of size 16
second = BitVecVal(int(second.encode('hex'), 16), 16)
print "second:", second
# The Z3 operation Concat concatenates two or more bit-vector expressions.
d = []
x = 0
while x < len(c):
# c[x] is a Bit-vector of size 8, second is a Bit-vector of size 16.
# In Z3, we have to do the "casting" ourselves.
# We use ZeroExt(8, c[x]) to convert c[x] into a Bit-vector of size 16,
# by adding 0-bits.
d.append(ZeroExt(8, c[x]) ^ second)
x += 2
print "d:", d
goal = str2array('\xbd\x23\x43\x23\x40\x23\x41\x23')
print "goal:", goal
# Note that, len(goal) == 2*len(d)
# We can use Concat to concatenate adjacent elements.
# We want each element of d[i] == Concat(goal[2*i], goal[2*i+1])
# We can use Z3 to find the 'b' that will satisfy these constraints
s = Solver()
# 's' is a Z3 solver object
i = 0
while i < len(d):
s.add(d[i] == Concat(goal[2*i+1], goal[2*i]))
i += 1
print s
# Now, 's' contains a set of equational constraints.
print s.check()
print s.model()

Related

Input in a cycle (Python)

I'm learning Python as my first language and now I trying to resolve this problem:
I have to make a loop where I ask the user which elements from a list they want to remove and then remove the elements selected. The loop stops only when the user insert a specific number that corresponds to the length of the list increased by 1 (so I won't have any problem).
I have another problem related to this:
elements_list = ['a','b','c','d']
length_list = len(elements_list)
for i in range(0, length_list):
print (str(i) + str(')') + elements_list[i])
This will print the list starting with 0:
0) a
1) b
2) c
3) d
What do I have to do if I want the list start with 1? (if I use 1 instead of 0 in the range it doesn't print the first element of the list)
In Python, lists can be iterated directly, and enumerate is used to generate indexes. Its optional second parameter gives a starting number:
>>> elements = ['a','b','c','d']
>>> for i,v in enumerate(elements,1):
... print('{}) {}'.format(i,v))
...
1) a
2) b
3) c
4) d
If using Python 3.6+, formatting output is even more simple using f-strings:
>>> elements = ['a','b','c','d']
>>> for i,v in enumerate(elements,1):
... print(f'{i}) {v}')
...
1) a
2) b
3) c
4) d
Refs:
enumerate
str.format
Formatted string literals
One way would be to add a 1 in the range, then subtract a 1 from the index
elements_list=['a','b','c','d']
lenght_list=len(elements_list)
for i in range(1, lenght_list+1):
print (str(i) + str(')') + elements_list[i-1])
Edit: TheoretiCAL's approach is even more straight forward, simply adding 1 to the print statement achieves the same thing.

Comparing symbolic mathematical expressions with Python using Sympy

I would like to check which mathematical expressions are equal.
I want to do this using Python I tried it with Sympy.
My idea was to use simplify in order to reduce the expressions such that a pair that is equal will be reduced to the same expression.
Then I substract them all with each other in my two for loops and check if the result equals to zero.
Unfortunately no substraction results in zero which is very improbable to be correct.
I think that probably the simplify function does not really do what I need.
Is there a function in sympy to check if two expressions are indeed mathematically equal?
This is my code so far:
from sympy import *
a = symbols ('a')
b = symbols ('b')
n = symbols ('n')
m = symbols ('m')
x1=simplify(log(a,n**(log(b,a))))
x2=simplify(((a**n)/(b**m))**(1/b))
x3=simplify(b**(n*log(a)))
x4=simplify(log(b,n))
x5=simplify(a**((n-m)/b))
x6=simplify(n*(log(a)+log(b)))
x7=simplify(log((a**n)*(b**n)))
x8=simplify(a**(log(b**n)))
L=[x1,x2,x3,x4,x5,x6,x7,x8]
for i in range (0 , 6):
for k in range (i+1 , 7):
print(L[i]-L[k])
The a.equals(b) method will try really hard (including using random values for variables) to show that a == b. But be aware that two expressions might only be equal for a given range of values. So it might be better to indicate that your symbols are, for example, positive or integer as in Symbol('n', integer=True) or Symbol('a', positive=True). If you do that then simplify(a - b) will more likely reduce to 0 as will a.equals(b).
posify is a function which can replace symbols with symbols having positive assumptions; see below how x6 and x7 simplify when symbols are positive:
>>> from sympy import posify
>>> dif = x6 - x7
>>> dif.simplify() == 0
Ealse
>>> posify(dif)[0].simplify() # [0] gets the the positive-symbol expression
You can also make numerical substitutions yourself using x._random(lo,LO,hi,HI) where (lo, hi) are the lower and upper limit for the real part of the number and (LO, HI) are the same for the imaginary part, e.g. x._random(0,0,1,0) will give a random value that is real between 0 and 1. Create a replacement dictionary and replace the values and check the absolute value of the difference in a and b. Something like this (using the loop as you presented it above):
for i in range (0 , 6):
for k in range (i+1 , 7):
v = L[i]-(L[k])
reps = {i: i._random(0,0,1,0) for i in v.free_symbols}
v = v.xreplace(reps).n()
if abs(v) < 1e-9:
print(L[i],L[k],abs(v))
Another way to check if functions are equal would be to evaluate them at maybe a few thousand points and check the outputs.
from sympy import *
def generateOutput(L, x):
# x -> list of points to evaluate functions at (maybe randomly generated?)
# L -> input list of functions
# returns list of outputs of L[i] applied to x
a = symbols ('a')
b = symbols ('b')
n = symbols ('n')
m = symbols ('m')
x1=simplify(log(a,n**(log(b,a))))
x2=simplify(((a**n)/(b**m))**(1/b))
x3=simplify(b**(n*log(a)))
x4=simplify(log(b,n))
x5=simplify(a**((n-m)/b))
x6=simplify(n*(log(a)+log(b)))
x7=simplify(log((a**n)*(b**n)))
x8=simplify(a**(log(b**n)))
L=[x1,x2,x3,x4,x5,x6,x7,x8]
outputs = generateOutput(L)
# Compare outputs
From the docs:
The Eq function (from sympy.core.relational) looks like it is what you want. Note that if it is given more complex arguments, you will have to simplify to get a result (see last code example in link).
Note: Those for loops don't look right. The first one will only go through indices 0-5 and the second only through i+1 to 6, so the last item in the list will be skipped completely.

recursive function in python but with strange return

I am trying to solve a primary equation with several variables. For example:11x+7y+3z=20. non-negative integer result only.
I use code below in python 3.5.1, but the result contains something like [...]. I wonder what is it?
The code I have is to test every variables from 0 to max [total value divided by corresponding variable]. Because the variables may be of a large number, I want to use recursion to solve it.
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
testrest=equation(a[1:],b-a[0]*i,corelist)
if testrest:
total+=[testrest]
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
return relist
else:
return False
total=[]
re=equation([11,7,3],20,[])
print(re)
the result is
[[0, 2, 2], [...], [1, 0, 3], [...]]
change to a new one could get clean result, but I still need a global variable:
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
equation(a[1:],b-a[0]*i,corelist)
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
total+=[relist]
return
else:
return
total=[]
print(equation([11,7,3],20,[]))
I see three layers of problems here.
1) There seems to be a misunderstanding about recursion.
2) There seems to be an underestimation of the complexity of the problem you are trying to solve (a modeling issue)
3) Your main question exposes some lacking skills in python itself.
I will address the questions in backward order given that your actual question is "the result contains something like [...]. I wonder what is it?"
"[]" in python designates a list.
For example:
var = [ 1, 2 ,3 ,4 ]
Creates a reference "var" to a list containing 4 integers of values 1, 2, 3 and 4 respectively.
var2 = [ "hello", ["foo", "bar"], "world" ]
var2 on the other hand is a reference to a composite list of 3 elements, a string, another list and a string. The 2nd element is a list of 2 strings.
So your results is a list of lists of integers (assuming the 2 lists with "..." are integers). If each sublists are of the same size, you could also think of it as a matrix. And the way the function is written, you could end up with a composite list of lists of integers, the value "False" (or the value "None" in the newest version)
Now to the modeling problem. The equation 11x + 7y + 3z = 20 is one equation with 3 unknowns. It is not clear at all to me what you want to acheive with this program, but unless you solve the equation by selecting 2 independent variables, you won't achieve much. It is not clear at all to me what is the relation between the program and the equation save for the list you provided as argument with the values 11, 7 and 3.
What I would do (assuming you are looking for triplets of values that solves the equation) is go for the equation: f(x,y) = (20/3) - (11/3)x - (7/3)y. Then the code I would rather write is:
def func_f(x, y):
return 20.0/3.0 - (11.0/3.0) * x - (7.0/3.0) * y
list_of_list_of_triplets = []
for (x, y) in zip(range(100),range(100)):
list_of_triplet = [x, y, func_f(x,y)]
list_of_list_of_triplets += [list_of_triplet] # or .append(list_of_triplet)
Be mindful that the number of solutions to this equation is infinite. You could think of it as a straight line in a rectangular prism if you bound the variables. If you wanted to represent the same line in an abstract number of dimensions, you could rewrite the above as:
def func_multi_f(nthc, const, coeffs, vars):
return const - sum([a*b/nth for a,b in zip(coeffs, vars)])
Where nthc is the coefficient of the Nth variable, const is an offset constant, coeffs is a list of coefficients and vars the values of the N-1 other variables. For example, we could re-write the func_f as:
def func_f(x,y):
return func_multi_f(3.0, 20.0, [11.0, 7.0], [x,y])
Now about recursion. A recursion is a formulation of a reducible input that can be called repetivitely as to achieve a final result. In pseudo code a recursive algorithm can be formulated as:
input = a reduced value or input items
if input has reached final state: return final value
operation = perform something on input and reduce it, combine with return value of this algorithm with reduced input.
For example, the fibonacci suite:
def fibonacci(val):
if val == 1:
return 1
return fibonacci(val - 1) + val
If you wanted to recusively add elements from a list:
def sum_recursive(list):
if len(list) == 1:
return list[0]
return sum_recursive(list[:-1]) + list[-1]
Hope it helps.
UPDATE
From comments and original question edits, it appears that we are rather looking for INTEGER solutions to the equation. Of non-negative values. That is quite different.
1) Step one find bounds: use the equation ax + by + cz <= 20 with a,b,c > 0 and x,y,z >= 0
2) Step two, simply do [(x, y, z) for x, y, z in zip(bounds_x, bounds_y, bounds_z) if x*11 + y*7 + z*3 - 20 == 0] and you will have a list of valid triplets.
in code:
def bounds(coeff, const):
return [val for val in range(const) if coeff * val <= const]
def combine_bounds(bounds_list):
# here you have to write your recusive function to build
# all possible combinations assuming N dimensions
def sols(coeffs, const):
bounds_lists = [bounds(a, const) for a in coeffs]
return [vals for vals in combine_bounds(bounds_lists) if sum([a*b for a,b in zip(coeff, vals)] - const == 0)
Here is a solution built from your second one, but without the global variable. Instead, each call passes back a list of solutions; the parent call appends each solution to the current element, making a new list to return.
def equation (a, b):
result = []
if len(a) > 1:
# For each valid value of the current coefficient,
# recur on the remainder of the list.
for i in range(b // a[0]+1):
soln = equation(a[1:], b-a[0]*i)
# prepend the current coefficient
# to each solution of the recursive call.
for item in soln:
result.append([i] + item)
else:
# Only one item left: is it a solution?
if b%a[0] == 0:
# Success: return a list of the one element
result = [[b // a[0]]]
else:
# Failure: return empty list
result = []
return result
print(equation([11, 7, 3], 20, []))

How to check if sum of 3 integers in list matches another integer? (python)

Here's my issue:
I have a large integer (anywhere between 0 and 2^32-1). Let's call this number X.
I also have a list of integers, unsorted currently. They are all unique numbers, greater than 0 and less than X. Assume that there is a large amount of items in this list, let's say over 100,000 items.
I need to find up to 3 numbers in this list (let's call them A, B and C) that add up to X.
A, B and C all need to be inside of the list, and they can be repeated (for example, if X is 4, I can have A=1, B=1 and C=2 even though 1 would only appear once in the list).
There can be multiple solutions for A, B and C but I just need to find one possible solution for each the quickest way possible.
I've tried creating a for loop structure like this:
For A in itemlist:
For B in itemlist:
For C in itemlist:
if A + B + C == X:
exit("Done")
But since my list of integers contains over 100,000 items, this uses too much memory and would take far too long.
Is there any way to find a solution for A, B and C without using an insane amount of memory or taking an insane amount of time? Thanks in advance.
you can reduce the running time from n^3 to n^2 by using set something like that
s = set(itemlist)
for A in itemlist:
for B in itemlist:
if X-(A+B) in s:
print A,B,X-(A+B)
break
you can also sort the list and use binary search if you want to save memory
import itertools
nums = collections.Counter(itemlist)
target = t # the target sum
for i in range(len(itemlist)):
if itemlist[i] > target: continue
for j in range(i+1, len(itemlist)):
if itemlist[i]+itemlist[j] > target: continue
if target - (itemlist[i]+itemlist[j]) in nums - collections.Counter([itemlist[i], itemlist[j]]):
print("Found", itemlist[i], itemlist[j], target - (itemlist[i]+itemlist[j]))
Borrowing from #inspectorG4dget's code, this has two modifications:
If C < B then we can short-circuit the loop.
Use bisect_left() instead of collections.Counter().
This seems to run more quickly.
from random import randint
from bisect import bisect_left
X = randint(0, 2**32 - 1)
itemset = set(randint(0,X) for _ in range(100000))
itemlist = sorted(list(itemset)) # sort the list for binary search
l = len(itemlist)
for i,A in enumerate(itemlist):
for j in range(i+1, l): # use numbers above A
B = itemlist[j]
C = X - A - B # calculate C
if C <= B: continue
# see https://docs.python.org/2/library/bisect.html#searching-sorted-lists
i = bisect_left(itemlist, C)
if i != l and itemlist[i] == C:
print("Found", A, B, C)
To reduce the number of comparisons, we enforce A < B < C.

Python Itertools Permutations

I am currently writing a program that uses itertools, and one piece of it does not seems to functioning properly. I would like the input that determines the length of the lists the permutation function outputs to be equal to length of the list from which it generates its outputs. In other words, I have
import itertools
b = 0
c = 9
d = [0,1,2]
e = len(d)
while b < c:
d.append(b)
b = b+1
print([x for x in itertools.permutations(d,e)])
And I would like this to generate all the possible permutations of d that are equal to this length. I have been experimenting with this and it seems that second determiner must be an integer. I even tried making a new variable, f, and having f = int(e) and then replacing e with f in the print statement, but with no success. With either of these all I got was [()]
Thanks for your help.
You need to set e after you build the list. len(d) returns a value, not a reference to the list's length.
d = range(0,9) # build an arbitrary list here
# this creates a list of numbers: [0,1,2,3,4,5,6,7,8]
e = len(d)
print list(itertools.permutations(d, e))
Note that the number of permutations is very large, so storing all of them in a list will consume large amounts of memory - you'd be better off with this:
d = range(0,9)
e = len(d)
for p in itertools.permutations(d, e):
print p

Categories

Resources