How to compare two logical expressions for equality? - compare

I have two logical expression (just examples):
!(n >= x || n < -y)
and
n < x && n >= -y
Are there any tools out there to compare expressions like these to see if they are logically equal for all values? Or just to help me find the most compact/simple form?

The "most compact/simple form" answer would depend on your notion of compactness/simplicity. For instance, you can perform a number of simplification steps such as conversion to the conjunctive normal form (elimination of ||) followed by negation elimination (replacing !(n > y) by (n <= y)).
Equivalence of formulas F and G can be checked by taking the conjunction of F and the negation of G and checking for satisfiability of F && !G with, e.g., a constraints solver. You should be careful with your domain though since the result depends on your domain (integers, rationals, reals): 2 < n && n < 3 is not satisfiable for the integers, but it is satisfiable for the reals!

Related

Find a logical expression that is true if `n` is a multiple of `2019` and is not in the interval `(a, b)`

I had the task of finding a logical expression that would result in 1 if and only if a given number n is a multiple of 2019 and is NOT from the interval (a, b).
The textbook gave the following answer and I don't really understand it:
a>=n || b<=n && (n%3==0 && n%673==0)
The thing between those parantheses I understand to be equivalent to n%2019==0, so that's alright. But I don't understand why this works, I mean the && operator has higher priority that the || operator, so wouldn't we evaluate
b<=n && (n%3==0 && n%673==0)
first and only at the end if n<=a? I thought that if I were to do it, I would do it like this:
(a>=n || b<=n) && (n%3==0 && n%673==0)
So I just added that extra set of parantheses. Now we would check if the number is not in the interval (a, b), then we would check if it is a multiple of 2019 and then we would 'and' those to answers to get the final answer. This makes sense to me. But I don't understand why they omitted that set of parantheses, why would that still work? Shouldn't we consider that && has higher priority than ||, so we add an extra set of parantheses? Would it still work? Or is it me that is wrong?
Trying it out shows that the expression as written without the extra parentheses doesn't work:
bool expr(int n, int a, int b)
{
return a>=n || b<=n && (n%3==0 && n%673==0);
}
expr(1000, 2000, 2018) for example evaluates to true, even though it is not a multiple of 2019.
As you pointed out, the logical AND operator && has higher precedence than the logical OR operator || (reference), so the expression is equivalent to:
a>=n || (b<=n && (n%3==0 && n%673==0))
which is always true when n <= a, even if it's not a multiple of 2019.
A clearer expression would be:
(n % 2019 == 0) && (n <= a || n >= b)

Advice about how to make Z3 evaluate simple constraints faster

I'm trying to use Z3 (with C++ API) to check if lots of variable configurations satisfy my constraints, but I'm having big performance issues.
I'm looking for advice about which logic or parameter setting I might be able to use to improve the runtime, or hints about how I could try and feed the problem to Z3 in a different way.
Short description of what I'm doing and how I'm doing it:
//_______________Pseudocode and example_______________
context ctx()
solver s(ctx)
// All my variables are finite domain, maybe some 20 values at most, but usually less.
// They can only be ints, bools, or enums.
// There are not that many variables, maybe 10 or 20 for now.
//
// Since I need to be able to solve constraints of the type (e == f), where
// e and f are two different enum variables, all my
// enum types are actually contained in only one enumeration_sort(), populated
// with all the different values.
sort enum_sort = {"green", "red", "yellow", "blue", "null"}
expr x = ctx.int_const("x")
expr y = ctx.int_const("y")
expr b = ctx.bool_const("b")
expr e = ctx.constant("e", enum_sort)
expr f = ctx.constant("f", enum_sort)
// now I assert the finite domains, for each variable
// enum_value(s) is a helper function, that returns the matching enum expression
//
// Let's say that these are the domains:
//
// int x is from {1, 3, 4, 7, 8}
// int y is from {1, 2, 3, 4}
// bool b is from {0, 1}
// enum e is from {"green", "red", "yellow"}
// enum f is from {"red", "blue", "null"}
s.add(x == 1 || x == 3 || x == 3 || x == 7 || x == 8)
s.add(y == 1 || y == 2 || y == 3 || y == 4)
s.add(b == 0 || b == 1)
s.add(e == enum_value("green") || e == enum_value("red") || enum_value("yellow"))
s.add(f == enum_value("red") || f == enum_value("blue") || enum_value("null"))
// now I add in my constraints. There are also about 10 or 20 of them,
// and each one is pretty short
s.add(b => (x + y >= 5))
s.add((x > 1) => (e != f))
s.add((y == 4 && x == 1) || b)
// setup of the solver is now done. Here I start to query different combinations
// of values, and ask the solver if they are "sat" or "unsat"
// some values are left empty, because I don't care about them
expr_vector vec1 = {x == 1, y == 3, b == 1, e == "red"}
print(s.check(vec1))
expr_vector vec2 = {x == 4, e == "green", f == "null"}
print(s.check(vec2))
....
// I want to answer many such queries.
Of course, in my case this isn't hardcoded, but I read and parse the constraints, variables and their domains from files, then feed the info to Z3.
But it's slow.
Even for something like ten thousand queries, my program is already running over 10s. All of this is inside s.check(). Is it possible to make it run faster?
Hopefully it is, because what I'm asking of the solver doesn't look like it's overly difficult.
No quantifiers, finite domain, no functions, everything is a whole number or an enum, domains are small, the values of the numbers are small, there's only simple arithmetic, constraints are short, etc.
If I try to use parameters for parallel processing, or set the logic to "QF_FD", the runtime doesn't change at all.
Thanks in advance for any advice.
Is it always slow? Or does it get progressively slower as you query for more and more configurations using the same solver?
If it's the former, then your problem is just too hard and this is the price to pay. I don't see anything obviously wrong in what you've shown; though you should never use booleans as integers. (Just looking at your b variable in there. Stick to booleans as booleans, and integers as integers, and unless you really have to, don't mix the two together. See this answer for some further elaboration on this point: Why is Z3 slow for tiny search space?)
If it's the latter, you might want to create a solver from scratch for each query to clean-up all the extra stuff the solver created. While additional lemmas always help, they could also hurt performance if the solver cannot make good use of them in subsequent queries. And if you follow this path, then you can simply "parallelize" the problem yourself in your C++ program; i.e., create many threads and call the solver separately for each problem, taking advantage of many-cores your computer no doubt has and OS-level multi-tasking.
Admittedly, this is very general advice and may not apply directly to your situation. But, without a particular "running" example that we can see and inspect, it's hard to be any more specific than this.
Some Ideas:
1. Replace x == 1 || x == 3 || x == 3 || x == 7 || x == 8 with (1 <= x && x <= 8) && (x <= 1 || (3 <= x) && (x <= 4 || 7 <= x). Similar change with y.
rationale: the solver for linear arithmetic now knows that x is always confined in the interval [1,8], this can be useful information for other linear equalities/inequalities; it may be useful to also learn the trivial mutual exclusion constraints not(x <= 1) || not(3 <= x) and not(x <= 4) || not(7 <= x); there are now exactly 3 boolean assignments that cover your original 5 cases, this makes the reasoning of the linear arithmetic solver more cost-efficient because each invocation deals with a larger chunk of the search space. (Furthermore, it is more likely that clauses learned from conflicts are going to be useful with subsequent calls to the solver)
(Your queries may also contain set of values rather than specific assignments of values; this may allow one to prune some unsatisfiable ranges of values with fewer queries)
2. Just like #alias mentioned, Boolean variables ought to be Booleans and not 0/1 Integer variables. The example you provided is a bit confusing, b is declared as a bool const but then you state b == 0 || b == 1
3. I am not familiar with the enum_sort of z3, meaning that I don't know how it is internally encoded and what solving techniques are applied to deal with it. Therefore, I am not sure whether the solver may try to generate trivially inconsistent truth-assignments in which e == enum_value("green") e e == enum_value("red") are both assigned to true at the same time. This might be worth a bit of investigation. For instance, another possibility could be to declare e and f as Int and give them an appropriate interval domain (as contiguous as possible) with the same approach shown in 1., that will be interpreted by your software as a list of enum values. This should remove a number of Boolean assignments from the search space, make conflict clauses more effective and possibly speed-up the search.
4. Given the small number of problem variables, values and constraints, I would suggest you to try to encode everything using just the Bit-Vector theory and nothing else (using small-but-big-enough domains). If you then configure the solver to encode Bit-Vectors eagerly, then everything is bit-blasted into SAT, and z3 should only use Boolean Constraint Propagation for satisfiability, which is the cheapest technique.
This might be an X Y problem, why are you performing thousands of queries, what are you trying to achieve? Are you trying to explore all possible combination of values? Are you trying to perform model counting?

Linear Programming: Depict logical expression in a boolean variable

I have a mixed integer linear program (MIP or MILP).
In the end I want a boolean variable im my linear program, that has the following properties.
I have two variables:
boolean b.
real x, with x being 0 or larger.
What I want to achieve is:
b == false if x == 0.
b == true if x > 0.
I found a way to depict if x is in specific range (e.g. between 2 and 3) via:
2*b <= x
x <= 3*b
The problem with the above testing formula is, that b will be true if x is in the given range and false if outside that range.
Does anybody know a way to set a boolean variable to false if x == 0 and to true if x is larger than 0?
If U is an upper bound of x then
if x > 0 ==> b == 1
can be made as
x <= U*b
The second part (x == 0 => b == 0) needs to be modified to
x < epsilon ==> b == 0
which can be made as
b <= 1 + x - epsilon
where epsilon is a small number. Other than good practice this is necessary, because solvers do not work in rational arithmetic (although there are some research efforts to make them do so), but with certain precision thresholds, and therefore quantities such as 10e-12 are treated as zero.
I hope this helps!
You could use the signum function http://en.wikipedia.org/wiki/Signum_function take the absolute value and negate it. Since you didn't name a specific programming language I keep it general.

How to assign binary variable in AMPL in respect to another variable

I have a problem with AMPL modelling. Can you help me how to define a binary variable u that suppose to be equall to 0 when another variable x is also equall to 0 and 1 when x is different than 0?
I was trying to use logical expressions but solver that I am working with (cplex and minos) doesn't allow it.
My idea was:
subject to:
u || x != u && x
Take M a 'big' constant such as x < M holds, and assume x is an integer (or x >= 1 if x is continuous). You can use the two constraints:
u <= x (if x=0, then u=0)
x <= M*u (if x>0, then u=1)
with u a binary variable.
If now x is continuous and not necessarily greater than 1, you will have to adapt the constraints above (for example, the first constraint here would not be verified with x=0.3 and u=1).
The general idea is that you can (in many cases) replace those logical constraints with inequalities, using the fact that if a and b are boolean variables, then the statement "a implies b" can be written as b>=a (if a=1, then b=1).

What is the difference between ! ( x < y ) and x >= y in C++?

Going through EASTL, I stumbled across a peculiar line of code. The following link shows the file with the line number of interest at 1870.
https://github.com/paulhodge/EASTL/blob/master/include/EASTL/algorithm.h
The code at that line is if(!(value < *i)). The comment says that "we always express value comparisons in terms of < or ==" without any explanation as to why this is so. There are also a few other areas where the same comment is placed but without any explanation.
Is there any benefit whatsoever to writing a comparison like that (maybe some context that I am overlooking)? If not, why did the author of EASTL deliberately wrote it in this particular fashion and even took the care to comment about it? Is consistency the only reason here?
It means you only need to provide < and == for container value types. It also means you reduce the amount of variability for those types (as all the algorithms use !(a<b) to mean a>=b and !(a==b) for a!=b); otherwise, you could have >= and != return inconsistent results.
In C++, you can overload the < operator so that it behaves differently than the opposite of >=, so they are not guaranteed to be equivalent.
Additionally, in any IEEE floating-point implementation, NaN < NaN is false, but so is NaN >= NaN, so !(NaN < NaN) is true even though NaN >= NaN is false.
I see at least one difference. If one of the numbers was QNAN (floating-point 0/0) then !(a < b) would've always return TRUE if any of a or b were QNAN, while it would've always returned false for a>=b
Using just the less-than operator, you can simulate all the other comparison operators. This makes it more consistent and allows you to use a single template parameter when you need to parameterize the comparison. The standard sorted containers and algorithms use std::less<T> as the default template comparator for example.
operation equivalent
x < y x < y
x > y y < x
x <= y !(y < x)
x >= y !(x < y)
x == y !(x < y) && !(y < x)
x != y (x < y) || (y < x)
For those operations where ordering is not important it's simpler and more efficient to use operator == instead.