Use z3Py to prove the equivalence/difference of ranges of two expressions - python

from z3 import *
s = Solver()
a, b = Ints("a b")
s.add(a > 2)
s.add(b > 0)
s.add(Or(Exists(a, ForAll(b, a != b)), Exists(b, ForAll(a, a != b))))
s.check() # print "unsat"
I am trying to prove the difference of ranges of a and b. This can be done by locating an assignment to b of value 1 which is beyond the range of a.
However, the program above gives unexpected unsat. I wonder why and whether there is more efficient way to achieve this goal.

ForAll means exactly that: all numbers, i.e. Exists(a, ForAll(b, a != b)) is always false because there is no Int that's different from all Ints and thus the third assertion is unsatisfiable all by itself. You want something like s.add(Exists(a, (Exists (b, And(Not(a > 2), b > 0))))).
Also, note that you use two different a and b. Exists(a, ...) does not quantify over an existing variable, but introduces a new variable that's accidentally called by the same name as your global (existential) a, b.

Related

Possible orderings of points of a pair of segments

Suppose a, b, c, and d hold floating point numbers. Suppose it must hold that a <= b and c <= d. Given these constraints I am trying to find all of the possible orderings using only <, and =. For example a < c = b < d is one possible ordering. b < c < a < d is not, due to the constraint that a <= b.
If you only allow < or = as operators, then the valid expressions will have the following properties
as the constraints only use ≤, whether the expressions use < or = does not matter
the constraints mean a must be before b and c must be before d
You can either generate all permutations and prune those which don't have a before b and c before d in them out, or you can generate based on those constraints, by deducing:
the first variable must be a or c
the second variable can either be the second variable in the constraint of the first, or other option for first
if the second is the same constraint as the first, then the other two must be the other two in order ( [a b c d] or [c d a b] )
if the variables for the constraints are interleaved, the third and forth can be in either order
That should give:
a∙b∙c∙d
a∙c∙b∙d
a∙c∙d∙b
c∙d∙a∙b
c∙a∙d∙b
c∙a∙b∙d
where ∙ can be either < or = in any of the positions.
If you also allow > as an operator, you get some which are always valid and some which can be either valid or not.
a∙b>c∙d
c∙d>a∙b
are valid as the > order doesn't occur between any of the variables that are paired in the constraints. I think any other cases with > it breaks the transitivity so you can't know whether the result obeys the constraints or not.
from itertools import zip_longest
def interleave_strings(a,b):
return ''.join(''.join(x) for x in zip_longest(a, b, fillvalue=''))
VARIABLE_ORDERINGS = ['abcd','acbd','cdab','cadb','cabd']
OPERATOR_COMBINATIONS = ['<<<','=<<','<=<','<<=','<==','=<=','==<','===']
for vars in VARIABLE_ORDERINGS:
for ops in OPERATOR_COMBINATIONS:
# only include a=b not b=a to elide equivalent expressions
if ops[0] == '=' and vars[0] > vars[1]: continue
if ops[1] == '=' and vars[1] > vars[2]: continue
if ops[2] == '=' and vars[2] > vars[3]: continue
print(interleave_strings(vars, ops))

Conditional Piecewise Function

This might be easier to explain by providing my attempt so far, then my intent+comments.
import numpy as np
from numpy import sqrt, arcsin, arcsinh
# Returns roots of quadratic (or lack of)
def roots(a, b, c):
b24ac = b*b - 4*a*c
if a == 0 or b24ac < 0:
return np.nan, np.nan
else:
l = (-b - sqrt(b24ac))/(2*a)
r = (-b + sqrt(b24ac))/(2*a)
if l > r:
l, r = r, l
return l, r
# Some numeric functions
def pw1(z, a, b, c):
return -arcsin((2*a*z+b)/sqrt(b*b - 4*a*c))/sqrt(-a)
def pw2(z, a, b, c):
return arcsinh((2*a*z+b)/sqrt(4*a*c - b*b))/sqrt(a)
# Function incorporating above definitions w/ conditions/domains
def func(z, a, b, c):
b24ac = b*b - 4*a*c
l, r = roots(*abc)
conditions = [(b24ac > 0 and a < 0) and (l < z and z < r),
(b24ac < 0 and a > 0)]
choices = [pw1(z, a, b, c),
pw2(z, a, b, c)]
return np.select(conditions, choices)
This is my attempt at creating a python function that is a conditional piecewise function. For the mathematically curious, this is a portion of a full definition of the integral of $[ax^2+bx+c]^{-1/2}$. The necessary specifics are that I need a function that is conditional on the domain AND other parameters. I've looked into numpy's piecewise and select functions. Piecewise, for its condition list, only accepts logic on the domain (not the parameters). Unless I'm missing something, this seems like it won't work for me. Select has given me the most success. The only issues I've had are it not evaluating domain conditions, over its domain:
---> conditions = [(b24ac > 0 and a < 0) and (l < z and z < r),
(b24ac < 0 and a > 0)]
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Lastly, it evaluates all choices (which are results as opposed to the functions that you give piecewise), then selects the one per the conditions list to return (commenting out the and (l < z... conditions):
c:\program files\python36\lib\site-packages\ipykernel_launcher.py:6:
RuntimeWarning: invalid value encountered in sqrt
I started this weeks ago with a bunch of elif statements. This worked only for floats, not arrays. I'm using numpy, and having this function (or any really) evaluate over a domain is what I'm after. I then learned about piecewise and select and began playing with these, being from numpy.
I'd really like a pythonic way to do this. One that evaluates over numpy arrays, and only for the desired condition/domain. So, behaves like piecewise but has versatile conditioning like select. Any help and suggestions are greatly appreciated! Thanks.
The b24ac identifier is certainly descriptive,
but most folks would probably name it discriminant.
use your own
You are complaining that you know how to compute the desired result,
but the numpy tools at hand don't seem a good fit.
So write your own function fn and use .apply(fn), or nditer.
Notice that you can arrange for all needed arguments to appear in extra columns,
and have the function handle a row at a time.
I heard no concerns about speed,
which would be the usual argument against such a custom function.
use np.piecewise
I agree with you that piecewise() appears to be appropriate to your needs.
The aspect that seemed missing was tailoring your functions with four parameters
before passing them to piecewise.
A good match for that need would be functools.partial().

how do you write out "A is greater than B, C, and D" in an efficient matter?

How can I make this statement shorter?
A simple solution is to combine B, C and D into one "value" using max, so you only perform one explicit test. For example, instead of:
if A > B and A > C and A > D:
just write:
if A > max(B, C, D):
An alternative but functionally similar approach would be to use all with a generator expression:
if all(A > x for x in (B, C, D)):
In theory, the generator expression approach is "faster", in that it performs fewer total comparisons and can short-circuit. That said, generator expressions have some overhead in terms of per loop Python byte code execution, so odds are the two perform similarly in practice, unless the objects in question have very expensive implementations of __gt__ (the overload for >).
Note that if you don't need a single unique maximum, a slightly different behavior, but with far fewer tests, could be performed:
maxval = max(A, B, C, D)
if maxval is A:
...
elif maxval is B:
...
elif maxval is C:
...
elif maxval is D:
...
This does differ behaviorally though; unlike the other code, a tie here is resolved semi-arbitrarily with only one element "winning", where the code you describe would treat a tie as "no winner". Replacing is with == and elif with if would treat a tie as "all tied for max are winners". It all depends on your desired behavior.

How to stop short circuiting in Python?

Python short circuits the logical operators.
for eg:
if False and Condition2:
#condition2 won't even be checked because the first condition is already false.
Is there a way to stop this behavior. I want it to check both the conditions and then perform the and operation(as done in c, c++ etc). It's useful when we are performing some operation along with the condition. e.g.:
if a < p.pop() and b < p.pop():
One way can be checking the conditions before and then comparing the Boolean values. But that would be wastage of memory.
if all([a < p.pop(), b < p.pop()])
This creates a list, which will be evaluated in its entirety, and then uses all to confirm that both values are truthy. But this is somewhat obscure and I'd rather suggest you write plain, easy to understand code:
a_within_limit = a < p.pop()
b_within_limit = b < p.pop()
if a_within_limit and b_within_limit:
If the conditions are booleans, as they are in your example, you could use & instead:
>>> a, b, p = 1, 1, [0, 0]
>>> (a < p.pop()) & (b < p.pop())
False
>>> p
[]
You can use the all() and any() built-in functions to somehow emulate the and and or operators. Both take an iterable of boolean-likes values as parameter. If you give it a literal tuple or list, all members will be fully evaluated:
# all emulates the and operator
if all((False, Condition2)):
do_stuff()
# any emulates the or operator
if any((False, Condition2)):
do_stuff()
Short answer: No, you cannot stop it to do this.
For example:
av = p.pop()
bv = p.pop()
if a < av and b < bv:
pass
Or:
av, bv = p.pop(), p.pop()
if a < av and b < bv:
pass
Also, there is no waste of memory in these examples. In Python, almost everything is done by reference. The value object being popped already exists somewhere. Even the scalars like strings, ints, etc are objects (some of them are slightly optimized). The only memory changes here are (1) the creation of a new variable that refers to the same existing object, and (2) removal of the record in the dict at the same time (which referred to that object before popping). They are of the similar scale.

Splitting a string in Python to 3 segments appointed to 3 variables depending on item count

I'm new to Python and struggling to solve the following issue the most Pythonic way.
I have a string (Example states given below) which needs to be split (.split('/', 2)) and appointed (up) to 3 variables (vars. a, b and c). The string is a URL which I need to split into 3 segments.
The string and its segments can be the following examples:
'seg_a/seb_b/the_rest' -> a = seg_a, b = seg_b, c = the_rest
'seg_a/the_rest' -> a = seg_a, b = None, c = the_rest
'seg_a' -> a = seg_a, b = None, c = None
Note: No obligation exists to have None value given if nothing else gets appointed. They simple may not exist (b in ex. 2, b and c in ex. 3).
If split results in 1 item, it's given to variable a.
If split results in 2 items, it's given to variable a and c
If split results in 3 items, then it's segments are given to variables a, b and c
I have found 2 methods achieving this, both seem not Pythonic, hence resulting in this question.
Method A:
Split.
Count.
Depending on count, appoint segments to variables with IF.. Elif.. Elif.. Else. statement
Method B:
Use list comprehension and nested Try-Except blocks. Ex:
try:
a, b, c = [i for i in to_split.split("/", 2)]
except ValueError:
try:
a, c = [i for i in to_split.split("/", 1)]
b = None
except ValueError:
a = to_split
b, c = None, None
My question (short):
What is the correct, Pythonic way of splitting this string to its
segments and appointing them to variables a, b and c?
I would do:
l = to_split.split("/", 2)
a, b, c = l + [None] * (3 - len(l))
IMHO, what is most Pythonic isn't what's most clever. If something is simple, concise, and comprehensible at a glance, then use it and get on with your day. If the rules you want to impose are
If split results in 1 item, it's given to variable a.
If split results in 2 items, it's given to variables a and c.
If split results in 3 items, it's given to variables a, b and c.
Then just implement that, Method A-style.
p = to_split.split("/", 2)
if len(p) == 1:
a, = p
elif len(p) == 2:
a, c = p
elif len(p) == 3:
a, b, c = p
else:
raise ValueError("could not parse {}".format(to_split))
I can read this and know exactly what it's doing. If there's a bug in there -- say I've swapped b and c when len(p) == 2 -- it's easy to fix once I see the problem.
It does seem a little strange that you're willing to let variables be undefined -- you must branch later to avoid getting a NameError, and that could, and probably should, be avoided with some refactoring. In my experience, something is probably a little off elsewhere. Even without changing anything else, I'd include a, b, c = [None]*3, myself.
One rule which helps keep code maintainable is that we should try to minimize the distance between what we would tell someone an algorithm is supposed to do and how we told the computer what to do. Here, since what you want to do is almost transcribable directly into Python, I'd just do that.
You could try:
a,b,c = (to_split("/",2) + [None]*3)[0:3]
However I agree with #DSM: the most pythonic way is not always the best approach to solve a problem. It could be ok at first, but a more verbose code works best in terms of readability.
That's one of the reasons I love Python: there are several ways to solve a problem, and it's up to the developer to choose the best according to his/her needs.

Categories