Linearization of if-then constraint - python

I'm trying to linearize a constraint of this form:
if a == b then c = 1
where a and b are positive integers and c is a binary variable.
I'm looking for a solution like this one https://math.stackexchange.com/questions/2792360/how-to-linearize-if-then-constraint
which doesn't work in this case.
Thanks to anyone who can help me.

The implication
a = b => c = 1
(a,b: integer variables, c: a binary variable)
can be re-stated as:
c = 0 => a >= b + 1
or
a <= b - 1
(Using that a,b are integers). An "or" needs an extra binary variable. So we can write:
a >= b + 1 - M δ - M c
a <= b - 1 + M (1-δ) + M c
δ ∈ {0,1}
Here M is a large enough constant (to be chosen with care).

Related

How to implement Modular Exponentiation Code

Please I was learning from the book Introduction to algorithm (Chapter 31 page 957) and came across this pseudocode. This pseudocode is how we can implement the modular-exponentiation. The pseudocode is as follows
MODULAR-EXPONENTIATION(a,b,n)
1 c = 0
2 d = 1
3 let <b_k,b_(k-i),....b_0> be the binary representation of b
4 for i = k downto 0
5 c = 2c
6 d = (d.d) mod n
7 if b_i == 1
8 c = c + 1
9 d = (d.a) mod n
10 return d
Then I tried to implement it in python
def modExpn(a,b,n):
c = 0
d = 1
binary_of_b = f'{b:b}'
len_of_b = len(binary_of_b)
for i in range(len_of_b,0,-1):
val = i - 1
c = 2 * c
d = (d * d) % n
if binary_of_b[val] == '1':
c = c + 1
d = (d * a) % n
return d
But when I tried running the function (modExpn) with a = 7,b=560 and n = 561 the output I had was 415 but the right answer is 1. Please where am I going wrong ?
You messed up while translating these parts from the pseudocode into actual code:
3 let <b_k,b_(k-i),....b_0> be the binary representation of b
4 for i = k **downto** 0
These instructions say that you should iterate from the left-most digit (b_k) of the binary representation to the right-most (b_0) since you need to go from k down to 0.
When you transform, for instance, 8 to binary you get "1000", and in Python the index of the left-most digit will be 0 and not len("1000") - 1 as you are doing.
In other words, if you just do:
for bin_digit in binary_of_b:
and later:
if bin_digit == '1':
your code is going to work.

Plus or minus an array by an array and store in a dictionary

I have done a ton of preprocessing and math on this data to arrive at two equally sized 3xN numpy arrays. A and B.
A = integers that have been classified as labels to predict B.
B = time series data.
I also have C which is just B[1:]
A and B are equal at their respective time steps and I can't figure out a better way to make a list of the next time step of B, so I have A[0:-1], B[0:-1] and C[1:])
I know that A + or - B is always == to at least 1 integer in C.
Example:
if A = [2,3,4] and B = [5,2,1] I know that at least 1 of C will be a 7,8,1,3, or any other combination of those numbers + or - each other.
How can I make a simple function to do this operation and check if it IS == to C and then store it as a key in a dictionary? The goal would be to create a neural network once this is complete to evaluate new data.
Just to give an example, if I understand what you are looking for:
a = [2,3,4]
b = [5,2,1]
c = set(b[1:])
sums = set([ aa + bb for aa in a for bb in b ])
subs1 = [ (aa - bb) for aa in a for bb in b if (aa - bb) > 0]
subs2 = [ bb - aa for bb in b for aa in a if (bb - aa) > 0]
subs = set(subs1 + subs2)
print(sums)
print(subs)
print(c)
print(len(sums & c)) #=> 0 c does not contains any of sums
print(len(subs & c)) #=> 2 c contains two of subs

Why do these two python functions return different results?

1-
def fib1(n):
a = 0
b = 1
while a < n:
print b
a = b
b = a+b
2-
def fib2(n):
a, b = 0,1
while a < n:
print b
a,b = b, b+a
On execution:
fib1(10) I got the wrong answer: 0 1 2 4 8
fib2(10) I got the right answer: 0 1 1 2 3 5 8
In fib 1
a = b
overwrites the value of a,
which means a is no longer the right value for the statement
b = a+b
However, in your second example both those things happen at the same time on the line a,b = a, b+a which means a is the right value still.
here's a quick answer:
the basic difference is the way the values of a and b are reassigned.
In fib1(), you have
a = b
b = a + b
while in fib2(), you have
a, b = b, b + a
Now, these two looks equal statements but they are not.
Here's why:
In fib2(), you assign the values of the tuple (b, b + a) to the tuple (a, b). Hence, reassignment of values are simultaneous.
However, with fib1(), you first assign value of b to a using a = b and then assign the value a + b to b. Since you have already changed value of a, you are in effect doing
b = a + b = b + b = 2b
In other words, you are doing a, b = b, 2b and that is why you are getting multiples of 2 rather than the fibonacci sequence.
fib1 contains a classic bug. It is in the same realm as that of swapping values of two variables. Think about how you would have done that in C or C++.
int a = 3;
int b = 5;
int temp;
temp = a; /* 3 */
a = b; /* 5 */
b = temp; /* 3, hence swapped */
There is a way to do without temp, although there are intermediate calculations involved. Now in Python, if you are not going to exploit the tuple unpacking feature, you have to involve a temp variable.
a = 3
b = 5
temp = a
a = b
b = temp
OR
a = 3
b = 5
a_ = (a+b)/2 - (a-b)/2 # 5.0
b_ = (a+b)/2 + (a-b)/2 # 3.0
Better use the tuple unpacking as in fib2.

difference between single and multiple assignments

I want to calculate the Fibonacci series in Python 3.5
If I do:
a = 0
b = 1
while b < 100:
print(b)
a, b = b, a + b
I get the right result, but if I do:
a = 0
b = 1
while b < 100:
print(b)
a = b
b = a + b
It simply does not work.
Why is this?
When you do this
a = b
b = a + b
then the assignment to a is executed first, and then the assignment to b, but at this time, a already has a new value. In effect, this is the same as
a = b
b = b + b # now a is the same as b
With the "double assignment", the two variables are updated at the same time
a, b = b, a + b
This assigns the tuple (b, a + b) to the tuple (a, b), using tuple-unpacking to distribute the values to a and b. You could think of this as being roughly equivalent to
temp = b, a + b
a = temp[0]
b = temp[1]
In the first iteration, the value of a changes to 1 which calculates b differently than in the second, where a + b = 2. In the first example, a + b = 1. At least, that's what it looks like to me.
In the first instance, inside the loop during the first run,
a, b = 1, 0+1
Leading a and b to be 1 and 1
In the second instance,
a = 1
b = 1 + 1
Leading a and b to be 1 and 2
The difference is that in the second instance, you're updating the value of b with an already updated value of a. Whereas in the first instance you're updating the value of b using the old value of a.

Sum of 2 elements from 2 ranges that will be one given number

I need to make a quick algorithm(I already made a slow one) which will find the number of all possible values from two ranges of integer numbers (ranges can intersect or not) which sum will be the given number
I can represent it like an equation: z = x + y
where z is a known number and equals x plus y
z can be any number between 0 and 10^18
x belongs to a range of integer numbers [a..b], where 0 <= a <= b <= 10^18 and
the difference between the consecutive numbers is 1
y belongs to a range of integer numbers [c..d], where 0 <= c <= d <= 10^18 and
the difference between the consecutive numbers is 1
so I need to find the number(not their exact values) of all the possible variations of x and y from two sets of numbers which sum will be z
Example:
z = 5
first set: a = 1, b = 5(it means the set consists of 1,2,3,4,5)
second set: c = 1, b = 5
then the answer is 4, because all possible combinations are:
x = 4, y = 1
x = 3, y = 2
x = 2, y = 3
x = 1, y = 4
because theirs sums are 5's
The compulsory condition for an algrorithm is to work faster than 1 second
The following code works fine but only with numbers lesser than 1000000. It starts to work much slower with big numbers
with open(r"input.txt") as f:
n = int(f.readline()) # the given number
a = int(f.readline()) # the start position of the first set
b = int(f.readline()) # the end position of the first set
c = int(f.readline()) # the start position of the second set
d = int(f.readline()) # the end position of the second set
# print "n:",n,"a:",a,"b:",b,"c:",c,"d:",d
t = b - a + 1 # all posible variants of the first set
k = d - c + 1 # all posible variants of the second set
number_of_vars = 0
if t >= k:
while b >= a:
if (n - b <= d) \
and (n - b>= c):
number_of_vars += 1
b -= 1
else:
b -= 1
if t < k:
while d >= c:
if (n-d <= b) and (n-d >= a):
number_of_vars += 1
d -= 1
else:
d -= 1
print number_of_vars
No algorithm required -- just algebra:
It suffices to count the number of x in [a,b] for which z - x is in [c,d]
You need both a <= x <= b and c <= z - x <= d. The second inequality is equivalent to z - d <= x <= z - c hence you need
max(a, z - d) <= x <= min(b,z - c)
The number of such x is 0 if min(b,z - c) < max(a, z - d) otherwise it is
min(b,z - c) - max(a, z - d) + 1
In either case the number of solutions is
max(0, min(b,z - c) - max(a, z - d) + 1)
In your example a = c = 1 and b = d = z = 5 and
min(b, z - c) - max(a, z - d) + 1 = min(5,4) - max(1,0) + 1 = 4 - 1 + 1 = 4
One thing that you can use to reduce the checks in your algorithm is,
If the range for the 2 sets are overlapping, then you can cancel out some checks. Like in your example,
range for 1st set is 1 to 5
range for 2nd set is 1 to 5
So, if
x = 4, y = 1
is working, then
x = 1, y = 4
will also work. So you have to go only till half the number (i.e till 3 only in this case)
If only a part of the range is overlapping, then you can use the above method for that part, and the remaining part can be checked using normal method.

Categories