Cardinality constraints in MiniZinc - constraint-programming

The MiniZinc constraint solver allows to express cardinality constraints very easily using the built-in sum() function:
% This predicate is true, iff 2 of the array
% elements are true
predicate exactly_two_sum(array[int] of var bool: x) =
(sum(x) == 2);
The cardinality constraint is met, if and only if the number if true elements in the array of Boolean variables is as specified. Booleans are automatically mapped to integer values 0 and 1 to compute the sum.
I implemented my own cardinality constraint predicate as set of counter slices:
% This predicate is true, iff 2 of the array
% elements are true
predicate exactly_two_serial(array[int] of var bool: x) =
let
{
int: lb = min(index_set(x));
int: ub = max(index_set(x));
int: len = length(x);
}
in
if len < 2 then
false
else if len == 2 then
x[lb] /\ x[ub]
else
(
let
{
% 1-of-3 counter is modelled as a set of slices
% with 3 outputs each
array[lb+1..ub-1] of var bool: t0;
array[lb+1..ub-1] of var bool: t1;
array[lb+1..ub-1] of var bool: t2;
}
in
% first two slices are hard-coded
(t0[lb+1] == not(x[lb] \/ x[lb+1])) /\
(t1[lb+1] == (x[lb] != x[lb+1])) /\
(t2[lb+1] == (x[lb] /\ x[lb+1])) /\
% remaining slices are regular
forall(i in lb+2..ub-1)
(
(t0[i] == t0[i-1] /\ not x[i]) /\
(t1[i] == (t0[i-1] /\ x[i]) \/ (t1[i-1] /\ not x[i])) /\
(t2[i] == (t1[i-1] /\ x[i]) \/ (t2[i-1] /\ not x[i]))
) /\
% output 2 of final slice must be true to fulfil predicate
((t1[ub-1] /\ x[ub]) \/ (t2[ub-1] /\ not x[ub]))
)
endif endif;
This implementation is using a parallel encoding with fewer lines/variables between the slices:
% This predicate is true, iff 2 of the array
% elements are true
predicate exactly_two_parallel(array[int] of var bool: x) =
let
{
int: lb = min(index_set(x));
int: ub = max(index_set(x));
int: len = length(x);
}
in
if len < 2 then
false
else if len == 2 then
x[lb] /\ x[ub]
else
(
let
{
% counter is modelled as a set of slices
% with 2 outputs each
% Encoding:
% 0 0 : 0 x true
% 0 1 : 1 x true
% 1 0 : 2 x true
% 1 1 : more than 2 x true
array[lb+1..ub] of var bool: t0;
array[lb+1..ub] of var bool: t1;
}
in
% first two slices are hard-coded
(t1[lb+1] == (x[lb] /\ x[lb+1])) /\
(t0[lb+1] == not t1[lb+1]) /\
% remaining slices are regular
forall(i in lb+2..ub)
(
(t0[i] == (t0[i-1] != x[i]) \/ (t0[i-1] /\ t1[i-1])) /\
(t1[i] == t1[i-1] \/ (t0[i-1] /\ x[i]))
) /\
% output of final slice must be 1 0 to fulfil predicate
(t1[ub] /\ not t0[ub])
)
endif endif;
Question:
Does it make sense to use home-grown cardinality predicates? Or is the MiniZinc implementation of sum() beyond all doubts in terms of solution speed?
Update:
I am using Gecode as solver back-end.

Linear sums is typically one of the most significant constraints to implement well in a constraint solver, so for your case the initial version using a simple sum is much better. In particular, the propagator in Gecode that implements the Boolean sum is heavily optimized to be as efficient as possible.
As a general rule, it is typically a good idea to use the constraints that are available. In particular, if what one is doing maps well to a global constraint that is typically a good idea. A related example would be if you want to count the occurrences of several different numbers in an array of integers, in which case the global cardinality constraint is very useful.
For completeness: When using lazy clause generation solvers (Chuffed for example), (novel) decompositions may sometimes be surprisingly useful. But that is a much more advanced topic.

Related

Difference between `==` and `and`

def pos_neg(a, b, negative):
if negative:
return (a < 0 and b < 0)
else:
return ((a < 0 == b > 0) or (a > 0 == b < 0))
so basically I tried some basic problems.
I just started out and went to https://codingbat.com/prob/p162058 to try it and don't understand why if I were to replace the '==' with 'and' it would work? Thanks.
Oh, I got it now, thanks guys. :D
(this python community is fire!!!)
Since you're learning, you might be interested in seeing that this is an equivalent function.
basically it does a bit wise & and returns true if the result is < 0
else a bit wise exclusive or and returns true if the result is < 0
def pos_neg(a , b, negative):
if negative:
return (a & b) < 0 # both sign bits set (i.e. neg), return true
else:
return (a ^ b) < 0 # different signs, return true
In both cases, it is the sign bit of the result that is of concern. If the bit is set then the value will be negative (hence the comparison to < 0)
and is a logical operator and returns true only when both the expressions we are using it on are true.
== is used for comparisons and returns true when both expressions are equal; they don't need to be true.
To give you an example False == False will return True but False and False will return False.
This "==" means equals to, belonging to Python Comparison Operators, used to compare two values.
and language keyword "and" it is for Python Logical Operators used to combine conditional statements.
You should check out this, it may solve others doubts you have.
W3Schools
All your relational operator usages (i.e. a < 0, b < 0, etc.) result to a boolean value and thus these are known as boolean expressions.
When you put a < 0, think of it like a test of: "is a less than 0, true or false?".
So, if both a and b are negative (i.e. less than zero), their expressions will return true.
So on the line return a < 0 and b < 0, replacing and with == is like saying return true == true. Without the change it'd be return true and true.
Note: This does not mean == is the same as and. == checks for equality of the left-hand side to the right-hand side (e.g. 1 == 1) and gives a true or false value depending on the result of equality. and checks for if the left-hand side results to a true statement and if the right-hand side results to a true statement in order to result to a true expression.

Parse error: The level of the expression or operator substituted for 'Def' must be at most 0

I have two specs: System and SystemMC. The System spec is the "nice" spec of the system I am specifying, useful for documentation. It defines a CONSTANT MessyAction(_) (in the actual specs I am writing, a hash function) that is messy to specify in an efficiently model-checkable way and so would reduce spec readability. I implement MessyAction(_) in the SystemMC spec, so I can model-check the System spec. However, the parser gives the following error in the SystemMC spec:
Level error in instantiating module 'System': The level of the expression or operator substituted for 'MessyAction' must be at most 0.
What does this error mean, and how can I accomplish my goal of model-checking the System spec without adding a bunch of stuff to it that is optimized for TLC? Here is the System spec:
------------------------------- MODULE System -------------------------------
EXTENDS
Naturals
CONSTANTS
MessyAction(_)
VARIABLES
Counter
-----------------------------------------------------------------------------
TypeInvariant ==
/\ Counter \in Nat
Init ==
/\ Counter = 0
Increment ==
/\ Counter' = Counter + 1
/\ MessyAction(Counter)
Next ==
\/ Increment
=============================================================================
Here is the SystemMC spec:
------------------------------ MODULE SystemMC ------------------------------
EXTENDS
Naturals
CONSTANTS
MaxCounterValue
VARIABLES
Counter,
PastValues
ASSUME MaxCounterValue \in Nat
-----------------------------------------------------------------------------
MessyAction(c) ==
/\ PastValues' = PastValues \cup {c}
S == INSTANCE System
TypeInvariant ==
/\ PastValues \subseteq Nat
/\ S!TypeInvariant
Init ==
/\ PastValues = {}
/\ S!Init
Increment ==
/\ Counter < MaxCounterValue
/\ S!Increment
Next ==
\/ Increment
=============================================================================
Per Leslie Lamport's reply here, when you instantiate a non-constant module (a module containing variables) like System, the CONSTANT entities can only be instantiated by other constants. So, in SystemMC you can rename MessyAction(_) to MessyActionImpl(_), define MessyAction(_) as a CONSTANT, then in the model define MessyAction(c) as MessyActionImpl(c). The System spec is unchanged, but here's the new SystemMC spec:
------------------------------ MODULE SystemMC ------------------------------
EXTENDS
Naturals
CONSTANTS
MessyAction(_),
MaxCounterValue
VARIABLES
Counter,
PastValues
ASSUME MaxCounterValue \in Nat
-----------------------------------------------------------------------------
MessyActionImpl(c) ==
/\ PastValues' = PastValues \cup {c}
S == INSTANCE System
TypeInvariant ==
/\ PastValues \subseteq Nat
/\ S!TypeInvariant
Init ==
/\ PastValues = {}
/\ S!Init
Increment ==
/\ Counter < MaxCounterValue
/\ S!Increment
Next ==
\/ Increment
=============================================================================
When you create a model in the toolbox, define the value of the MessyAction(_) constant as MessyActionImpl(_):
End result:
Voila, dependency injection for TLA+!

If elif one liner

if i == len(a):
tempList.extend(b[j:])
break
elif j == len(b):
tempList.extend(a[i:])
break
I am using this in a mergesort-program in Python. Is there any way to put this into a oneliner?
Maybe, but let's give a dedicated non-answer: don't even try.
You don't write your code to be short. You write it so that:
it gets the job done in a straight forward manner
it clearly communicates its meaning to human readers
The above code does that already.
In other words: of course being precise is a valuable property of source code. So, when you have to equally readable pieces of code doing the same thing, and one version is a one-liner, and the other is way more lengthy - then you go for the short version.
But I very much doubt that the above can be expressed as readable as above - with less code.
You can use and and or boolean operations to make a pretty readable one-liner:
l = []
a = [1,2,3,4]
b = [8,9,10]
i = 4
j = 2
l.extend(i == len(a) and b[j:] or j == len(b) and a[i:] or [])
l == [10]
i = 0
j = 3
l.extend(i == len(a) and b[j:] or j == len(b) and a[i:] or [])
l == [10, 1, 2, 3, 4]
This example uses next properties:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
We have to add or [] to mitigate TypeError: 'bool' object is not iterable exception raised when i == len(a) and j > len(b) (e.g. i == 4 and j == 5).
I'd still prefer an expanded version though.

Check if X is a multiple of Y, where Y may be zero

I have two numbers, X and Y, and I want to assert that X is a multiple of Y -- i.e., I want to assert that there exists some arbitrary integer n such that Y * n == X.
If Y is guaranteed to be greater than zero, I can write
assert!(x % y == 0)
But in my case, Y may be zero. If Y is zero, then X must also be zero, so I could write
if y == 0 {
assert!(x == 0);
} else {
assert!(x % y == 0);
}
But this is 5 lines long and has two branches vs. the assert's single branch. Is it possible to do this in one line in an elegant way?
if is an expression in Rust, so you could write
assert_eq!(0, if y == 0 { x } else { x % y });
As mentioned in the comment, you could also write
assert!(y == 0 && x == 0 || x % y == 0);
but the if expression approach is more general.
You could also use checked_rem so that x.checked_rem(0) == None, but that is not going to be simpler than an if expression.
assert_eq!(0, x.checked_rem(y).unwrap_or(x));

and operator with random

i dont understand why the code bellow doesnt work properly. If both variables a and b < 0 it should print that both numbers are negative,else the last message. But it just dont work so, what am i doing wrong? please help!
import random
while True:
input()
a=random.randint(-9,9)
b=random.randint(-9,9)
print(a,b)
if a and b < 0:
print("2 negative numbers:",a,b)
else:
print("one or both of the numbers are positive!")
I'm running this on python 3.4.
I think you're a little confused about how operators distribute.
When you have
if a and b < 0
it doesn't mean
if (both a and b) < 0
but instead
if (a) and (b < 0)
which is equivalent to
if (a != 0) and (b < 0)
since "numeric zero of all types ... evaluates to false" (see the reference on booleans on docs.python.org)
Instead, you want
if a < 0 and b < 0
which will tell you if both a and b are less than zero.
Evaluating Both Operands will resolve the issue. Here both Operands are expressions which results in true or false, so if both result in true; you will get your required result.
if ((a < 0) and (b < 0)):
You are evaluating just a, not it's relation to 0:
if a < 0 and b < 0:
This:
a and b < 0:
Is equivalent to this:
(a) and (b < 0):
(a) is False when a equals 0 and True otherwise. Therefore, due to short-circuiting b < 0 isn't even evaluated.
As a fix you may use all method:
all(i < 0 for i in (a, b))

Resources