I am interested in using one-line ternary expressions instead of traditional multiline if-else blocks. However, expressions comparing is None give different results.
Here is an example comparing multiline and one-line variants of two forms of a conditional expression for a predicate:
if pred is not None
if pred is None
Code
import operator as op
# First form
def is_not_none_multiline(a, b, pred=None):
if pred is not None:
predicate = pred
else:
predicate = lambda x, y: x + y
return predicate(a, b)
def is_not_none_oneline(a, b, pred=None):
predicate = pred if pred is not None else lambda x, y: x + y
return predicate(a, b)
# Second Form
def is_none_multiline(a, b, pred=None):
if pred is None:
predicate = lambda x, y: x + y
else:
predicate = pred
return predicate(a, b)
def is_none_oneline(a, b, pred=None):
predicate = lambda x, y: x + y if pred is None else pred
return predicate(a, b)
Tests
Here are tests for optional arguments in mutliline and one-line variants. The final result was unexpected:
assert is_not_none_multiline(1, 2) == 3
assert is_not_none_oneline(1, 2) == 3
assert is_not_none_multiline(1, 2, pred=op.mul) == 2
assert is_not_none_oneline(1, 2, pred=op.mul) == 2
assert is_none_multiline(1, 2) == 3
assert is_none_oneline(1, 2) == 3
assert is_none_multiline(1, 2, pred=op.mul) == 2
assert is_none_oneline(1, 2, pred=op.mul) == 2
# ----> 4 assert is_none_oneline(1, 2, pred=op.mul) == 2
# AssertionError:
Although pred is not None works as one-line:
predicate = pred if pred is not None else lambda x, y: x + y
pred is None does not work as one-line:
predicate = lambda x, y: x + y if pred is None else pred
Details
Apparantly, the pred function is not evaluated when passed in as a keyword to is_none_oneline(). Rather, it is returned:
print(is_none_oneline(1, 2, pred=op.mul))
# <built-in function mul>
This analysis was verified in a Python Tutor visualization when executing both variants of the second form (see visualizations here is not None multiline, is not None one-line, is None multiline, is None one-line).
Questions
It is unclear why an equivalent ternary expression returns a function rather than a computed value.
Can someone explain why the predicate is not evaluated in the second form - a one-line, pred is None expression?
How does one correctly write pred is None in one-line?
Just a simple case of operator precedence.
You're getting a callable which returns a callable. I think you wanted this instead, to make sure the conditional gets grouped the other way:
def is_none_oneline(a, b, pred=None):
predicate = (lambda x, y: x + y) if pred is None else pred
return predicate(a, b)
Related
This is an extension of the question:
Use Z3 to find counterexamples for a 'guess solution' to a particular CHC system?
In the below code, I am trying to use Z3 to get s counterexamples to a guess candidate for I satisfying some CHC clauses:
from z3 import *
x, xp = Ints('x xp')
P = lambda x: x == 0
B = lambda x: x < 5
T = lambda x, xp: xp == x + 1
Q = lambda x: x == 5
s = 10
def Check(mkConstraints, I, P , B, T , Q):
s = Solver()
# Add the negation of the conjunction of constraints
s.add(Not(mkConstraints(I, P , B, T , Q)))
r = s.check()
if r == sat:
return s.model()
elif r == unsat:
return {}
else:
print("Solver can't verify or disprove, it says: %s for invariant %s" %(r, I))
def System(I, P , B, T , Q):
# P(x) -> I(x)
c1 = Implies(P(x), I(x))
# P(x) /\ B(x) /\ T(x,xp) -> I(xp)
c2 = Implies(And(B(x), I(x), T(x, xp)) , I(xp))
# I(x) /\ ~B(x) -> Q(x)
c3 = Implies(And(I(x), Not(B(x))), Q(x))
return And(c1, c2, c3)
cex_List = []
I_guess = lambda x: x < 3
for i in range(s):
cex = Check(System, I_guess, P , B , T , Q)
I_guess = lambda t: Or(I_guess(t) , t == cex['x'])
cex_List.append( cex[x] )
print(cex_List )
The idea is to use Z3 to learn a counterexample x0 for guess invariant I, then run Z3 to learn a counterexample for I || (x == x0) and so on till we get s counterexamples. However the following code gives 'RecursionError: maximum recursion depth exceeded
'. I am confused because I am not even recursing with depth > 1 anywhere. Could anyone describe what's going wrong?
Your problem really has nothing to do with z3; but rather a Python peculiarity. Consider this:
f = lambda x: x
f = lambda x: f(x)
print(f(5))
If you run this program, you'll also see that it falls in to the same infinite-recursion loop, since by the time you "get" to the inner f, the outer f is bound to itself again. In your case, this is exhibited in the line:
I_guess = lambda t: Or(I_guess(t) , t == cex['x'])
which falls into the same trap by making I_guess recursive, which you did not intend.
The way to avoid this is to use an intermediate variable. It's ugly and counter-intuitive but that's the way of the python! For the example above, you'd write it as:
f = lambda x: x
g = f
f = lambda x: g(x)
print(f(5))
So, you need to do the same trick for your I_guess variable.
Note that since you're updating the function iteratively, you need to make sure to remember the function in each step, instead of using the same name over and over. That is, capture the old version each time you create the new function. When applied to the above case, it'll be something like:
f = lambda x: x
f = lambda x, old_f=f: old_f(x)
print(f(5))
This'll make sure the iterations don't clobber the captured function. Applying this idea to your problem, you can code as follows:
for i in range(s):
cex = Check(System, I_guess, P, B, T, Q)
I_guess = lambda t, old_I_guess=I_guess: Or(old_I_guess(t), t == cex[x])
cex_List.append(cex[x])
When run, this prints:
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
without any infinite-recursion problem. (Whether this is the correct output or what you really wanted to do, I'm not sure. Looks to me like you need to tell z3 to give you a "different" solution, and maybe you've forgotten to do that. But that's a different question. We're really discussing a Python issue here, not z3 modeling.)
When using a conditional return, if you attempt to return more than one value from function, the function behaves erratically with regard to the actual return value.
def test_function(x,y, diagnostic:bool=False):
w = x*y
z = []
if diagnostic:
z = [w,w*2]
return z, w if diagnostic else w
print(test_function(3,4)) # output tuple ([],12)
# lets switch order of the return from z,w to w,z
def test_function(x,y, diagnostic:bool=False):
w = x*y
z = []
if diagnostic:
z = [w,w*2]
return w,z if diagnostic else w
print(test_function(3,4)) # output tuple (12,12)
# lets try retun the diagnostic value itself to see what function things is happening
def test_function(x,y, diagnostic:bool=False):
w = x*y
z = []
if diagnostic:
z = [w,w*2]
return diagnostic if diagnostic else w
print(test_function(3,4)) # returns 12, so diagnostic is retuning false
# rewrite conditional to "if not"
def test_function(x,y, diagnostic:bool=False):
w = x*y
z = []
if diagnostic:
z = [w,w*2]
return w if not diagnostic else w,z
print(test_function(3,4)) # returns (12, [])
The problem is operator precedence: , has lower precedence than ... if ... else ..., so what you actually wrote is like return z, (w if diagnostic else w), or in the second function, it's like return w, (z if diagnostic else w).
The hint for this is that diagnostic is False but you're still returning a pair of values.
For the behaviour you want, you should write return (z, w) if diagnostic else w. Note that the brackets here are not needed to make it a tuple - it is a tuple either way - the brackets are to specify precedence.
If returning multiple values in a conditional return, the values must be explicitly returned as a tuple due to operator precedence:
def test_function(x,y, diagnostic:bool=False):
w = x*y
z = []
if diagnostic:
z = [w,w*2]
return (z, w) if diagnostic else w
print(test_function(3,4)) # returns 12
print(test_function(3,4, diagnostic=False)) # returns (12, [12, 24])
w, z = test_function(3,4, diagnostic=True)
print(w) # returns 12
print(z) # returns [12,24]
I'm trying to build a python function from a input given in Reverse Polish notation. My function is supposed to be able to take in x and y values as parameters and return the value of the function for the respective x and y.
My input is for example:
"x 1 + y 3 * +"
My expected result would be a function object similar to:
fun = lambda x,y: x+1+y*3
So that I can call fun(1,2) and get 9 as the result.
So far I can evaluate input without variables and give the result.
bin_ops = {
"+": (lambda a, b: a + b),
"-": (lambda a, b: a - b),
"*": (lambda a, b: a * b),
"/": (lambda a, b: a / b),
}
def eval(expression):
tokens = expression.split()
stack = []
for token in tokens:
if token in bin_ops:
arg2 = stack.pop()
arg1 = stack.pop()
result = bin_ops[token](arg1, arg2)
stack.append(result)
else:
stack.append(float(token))
return stack.pop()
txt = '2 1 + 2 3 * +'
print(eval(txt)) # prints 9.0
Can you help me how to build a function instead of directly the result
and how I can process variables (such as x and y) properly?
You can change your parsing code from creating values into creating functions that can be called with keyword arguments for final evaluation:
bin_ops = {
"+": lambda a, b: lambda **namespace: a(**namespace) + b(**namespace),
"-": lambda a, b: lambda **namespace: a(**namespace) - b(**namespace),
"*": lambda a, b: lambda **namespace: a(**namespace) * b(**namespace),
"/": lambda a, b: lambda **namespace: a(**namespace) / b(**namespace),
}
def eval(expression):
tokens = expression.split()
stack = []
for token in tokens:
if token in bin_ops:
arg2 = stack.pop()
arg1 = stack.pop()
result = bin_ops[token](arg1, arg2)
stack.append(result)
else:
try:
num = float(token)
except ValueError:
stack.append(lambda *, _token=token, **namespace: namespace[_token])
else:
stack.append(lambda *, _num=num, **namespace: _num)
return stack.pop()
txt = "x 1 + y 3 * +"
fun = eval(txt)
print(fun(x=2, y=4)) # prints 15.0
The way Python scopes work makes it a little tricky to generate functions that use variables from a loop. This is why I use token and num to set default values for arguments in our generated lambda functions, rather than using their names directly. If you just did lambda **namespace: namespace[token], you'd find that token had changed value as the loop kept running. The bin_ops code doesn't have that issue because the final functions are already nested in an extra scope, since the lambda a, b function is where we build the inner lambdas.
I need to implement some Grassmann variables in python (i.e. anti-commuting variables). In other words, I would like something with behavior as follows
>>> from sympy import *
>>> x, y = symbols('x y')
>>> y*x
-x*y
>>> y*y
0
One other feature I would need from this is the ability to give a canonical ordering to my variables. When I typed >>> y*x, it would certainly have been valid to also output y*x over -x*y. But, I would like the ability to choose that x should appear to the left of y (perhaps only after calling a function simplify(y*x)).
Does SymPy or some other library have this ability? If not, what would be the best way to go about implementing this myself (e.g. should I create a symbolic library myself, extend SymPy, etc.)?
You can make a new class inheriting from Symbol and change its behaviour on multiplication (__mul__) to the desired one.
To make this any useful, you need a canonic ordering anyway, which should be the same as SymPy’s (which at a quick glance appears to be by name, i.e., Symbol.name) to avoid problems.
from sympy import Symbol, S
class AnticomSym(Symbol):
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs,commutative=False)
def __mul__(self,other):
if isinstance(other,AnticomSym):
if other==self:
return S.Zero
elif other.name<self.name:
return -Symbol.__mul__(other,self)
return super().__mul__(other)
def __pow__(self,exponent):
if exponent>=2:
return S.Zero
else:
return super().__pow__(exponent)
x = AnticomSym("x")
y = AnticomSym("y")
assert y*x == -x*y
assert y*y == 0
assert y**2 == 0
assert y**1 == y
assert ((x+y)**2).expand() == 0
assert x*y-y*x == 2*x*y
Now, this still does not resolve complex products such as x*y*x*y correctly.
For this, we can write a function that sorts an arbitrary product (using bubble sort):
from sympy import Mul
def sort_product(product):
while True:
if not isinstance(product,Mul):
return product
arglist = list(product.args)
i = 0
while i < len(arglist)-1:
slice_prod = arglist[i]*arglist[i+1]
is_mul = isinstance(slice_prod,Mul)
arglist[i:i+2] = slice_prod.args if is_mul else [slice_prod]
i += 1
new_product = Mul(*arglist)
if product == new_product:
return new_product
product = new_product
z = AnticomSym("z")
assert sort_product(y*(-x)) == x*y
assert sort_product(x*y*x*y) == 0
assert sort_product(z*y*x) == -x*y*z
Finally, we can write a function that sorts all products within an expression by iterating through the expression tree and applying sort_product to every product it encounters:
def sort_products(expr):
if expr.is_Atom:
return expr
else:
simplified_args = (sort_products(arg) for arg in expr.args)
if isinstance(expr,Mul):
return sort_product(Mul(*simplified_args))
else:
return expr.func(*simplified_args)
from sympy import exp
assert sort_products(exp(y*(-x))) == exp(x*y)
assert sort_products(exp(x*y*x*y)-exp(z*y*z*x)) == 0
assert sort_products(exp(z*y*x)) == exp(-x*y*z)
Note that I may still not have accounted for every eventuality.
Wrzlprmft's answer is a great start so I will add the next logical step. Since you are asking for anticommuting symbols to be handled by a computer algebra system, it is reasonable to assume that you want to be able to differentiate with respect to them. This will require a function to overwrite sympy's product rule.
from sympy import Add, Mul, prod
from sympy.ntheory.multinomial import multinomial_coefficients_iterator
def AnticomDeriv(ptr, s, n):
args = ptr.args
m = len(args)
terms = []
factor = S.One
if isinstance(s, AnticomSym):
if n > 1:
return S.Zero
args = list(args)
for i in range(len(args)):
d = args[i].diff(s)
terms.append(factor * reduce(lambda x, y: x*y, (args[:i] + [d] + args[i + 1:]), S.One))
if isinstance(args[i], AnticomSym):
factor *= -1
return Add.fromiter(terms)
for kvals, c in multinomial_coefficients_iterator(m, n):
p = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)])
terms.append(c * p)
return Add(*terms)
Mul._eval_derivative_n_times = AnticomDeriv
This will give the following (correct) behaviour.
>>> x = AnticomSym('x')
>>> y = AnticomSym('y')
>>> expr = x*y
>>> expr.diff(x)
y
>>> expr.diff(y)
-x
I want to encode If-the-else in Z3 python, but cannot find any docs or sample on how to do that.
I have a sample code like below.
F = True
tmp = BitVec('tmp', 1)
tmp1 = BitVec('tmp1', 8)
Now how can I encode this condition into F:
if tmp == 1, then tmp1 == 100. otherwise, tmp1 == 0
Thanks so much.
You'll need Z3's If function:
def z3py.If ( a,
b,
c,
ctx = None
)
Create a Z3 if-then-else expression.
>>> x = Int('x')
>>> y = Int('y')
>>> max = If(x > y, x, y)
>>> max
If(x > y, x, y)
>>> simplify(max)
If(x <= y, y, x)
(from here)
You can use If for this. If takes three arguments: the condition, an expression that should be true if the condition is true and an expression that should be true if the condition is false. So to express your logic, you'd write:
If(tmp==1, tmp1==100, tmp1==0)