Fast computation for changing the leftmost different bit - python

Given the two number in 8-bit:
x = 0b11110111
y = 0b11001010
What I want to do is to compare x and y and change x only the first different leftmost bit based on y. For example:
z = 0b11010111 (Because the leftmost different bit between x and y is in the third place, therefore, change the third bit in x based on y and other remain the same.)
And my code is:
flag = True
for i in range(8):
if flag and x[i] != y[i]: # Change only the left-most different bit.
flag = False
else:
y[i] = x[i] # Otherwise, remain the same.
This could work find.
Buit the problem is if I have many pairs like:
for (x, y) in nums:
flag = True
for i in range(8):
if flag and x[i] != y[i]: # Change only the left-most different bit.
flag = False
else:
y[i] = x[i] # Otherwise, remain the same.
When nums is large, then this process will be really slow.
So how can I improve the process of the problem?
BTW, this is the project of the deep learning task, so it can run on GPU, but I don't know whether it can be paralleled by GPU or not.

The function you're after:
from math import floor, log2
def my_fun(x, y):
return x ^ (2 ** floor(log2(x ^ y)))
z = my_fun(0b11110111, 0b11001010)
print(f'{z:b}')
Output:
11010111
The function does the following:
compute the XOR result of x and y, which will include the most significant bit where they differ as the most significant bit to be 1
compute the floor of the log2 of that value, and raising 2 to that power, to get a number that only has that bit set to 1
return the XOR of x and that number, flipping the relevant bit

Related

Sum of two squares in Python

I have written a code based on the two pointer algorithm to find the sum of two squares. My problem is that I run into a memory error when running this code for an input n=55555**2 + 66666**2. I am wondering how to correct this memory error.
def sum_of_two_squares(n):
look=tuple(range(n))
i=0
j = len(look)-1
while i < j:
x = (look[i])**2 + (look[j])**2
if x == n:
return (j,i)
elif x < n:
i += 1
else:
j -= 1
return None
n=55555**2 + 66666**2
print(sum_of_two_squares(n))
The problem Im trying to solve using two pointer algorithm is:
return a tuple of two positive integers whose squares add up to n, or return None if the integer n cannot be so expressed as a sum of two squares. The returned tuple must present the larger of its two numbers first. Furthermore, if some integer can be expressed as a sum of two squares in several ways, return the breakdown that maximizes the larger number. For example, the integer 85 allows two such representations 7*7 + 6*6 and 9*9 + 2*2, of which this function must therefore return (9, 2).
You're creating a tuple of size 55555^2 + 66666^2 = 7530713581
So if each element of the tuple takes one byte, the tuple will take up 7.01 GiB.
You'll need to either reduce the size of the tuple, or possibly make each element take up less space by specifying the type of each element: I would suggest looking into Numpy for the latter.
Specifically for this problem:
Why use a tuple at all?
You create the variable look which is just a list of integers:
look=tuple(range(n)) # = (0, 1, 2, ..., n-1)
Then you reference it, but never modify it. So: look[i] == i and look[j] == j.
So you're looking up numbers in a list of numbers. Why look them up? Why not just use i in place of look[i] and remove look altogether?
As others have pointed out, there's no need to use tuples at all.
One reasonably efficient way of solving this problem is to generate a series of integer square values (0, 1, 4, 9, etc...) and test whether or not subtracting these values from n leaves you with a value that is a perfect square.
You can generate a series of perfect squares efficiently by adding successive odd numbers together: 0 (+1) → 1 (+3) → 4 (+5) → 9 (etc.)
There are also various tricks you can use to test whether or not a number is a perfect square (for example, see the answers to this question), but — in Python, at least — it seems that simply testing the value of int(n**0.5) is faster than iterative methods such as a binary search.
def integer_sqrt(n):
# If n is a perfect square, return its (integer) square
# root. Otherwise return -1
r = int(n**0.5)
if r * r == n:
return r
return -1
def sum_of_two_squares(n):
# If n can be expressed as the sum of two squared integers,
# return these integers as a tuple. Otherwise return <None>
# i: iterator variable
# x: value of i**2
# y: value we need to add to x to obtain (i+1)**2
i, x, y = 0, 0, 1
# If i**2 > n / 2, then we can stop searching
max_x = n >> 1
while x <= max_x:
r = integer_sqrt(n-x)
if r >= 0:
return (i, r)
i, x, y = i+1, x+y, y+2
return None
This returns a solution to sum_of_two_squares(55555**2 + 66666**2) in a fraction of a second.
You do not need the ranges at all, and certainly do not need to convert them into tuples. They take a ridiculous amount of space, but you only need their current elements, numbers i and j. Also, as the friendly commenter suggested, you can start with sqrt(n) to improve the performance further.
def sum_of_two_squares(n):
i = 1
j = int(n ** (1/2))
while i < j:
x = i * i + j * j
if x == n:
return j, i
if x < n:
i += 1
else:
j -= 1
Bear in mind that the problem takes a very long time to be solved. Be patient. And no, NumPy won't help. There is nothing here to vectorize.

How do I find the Space Complexity of this code?

I've was writing some code in Python to solve the following problem:
"Implement the function fib(n), which returns the n^th number in the Fibonacci sequence,using only O(1) space."
Below is the code I wrote, but I'm unsure how to find its space complexity.
def fib(n):
x=0
y=1
z=0
for num in range(0,n):
if (num % 2) == 0:
z = x
x = x+y
print(x)
else:
y = x
x = x+z
print(x)
return x
To find space complexity, you look at any collections / data-structures you've made.
Any primitive values are constant space.
A range() is a generator function that can be considered as constant space since it does not need to maintain more state than its current value and a step, as compared to a list(range()), which allocates memory for all values between start and end.

Z3: Find if variable is multiple of some other number

I would like to create a constraint that makes sure that a Real value is quantized to some tick value.
TICK = 0.5
x = Real('x')
solve(x % TICK == 0)
Unfortunately, this does not work with Real numbers (it works with Int and FP).
Another solution that I thought of was to create a set of valid numbers and check whether the number is part of the set, however the set would need to be really big.
Is there any other solution?
As Christoph mentioned, computing the modulus of a real-number isn't really meaningful. But your question is still valid: You're asking if x is an integer multiple of TICK. You can do this as follows:
from z3 import *
TICK = 0.5
x = Real('x')
k = Int('k')
solve(x == 1, ToReal(k) * TICK == x)
solve(x == 1.2, ToReal(k) * TICK == x)
This prints:
[k = 2, x = 1]
no solution
Note that unless x is a constant, this'll lead to a mixed integer-real arithmetic, and it might give rise to non-linear constraints. This can make it hard for the solver to answer your query, i.e., it can return unknown or take too long to respond. It all depends on what other constraints you have on x.

Why this sudoku solver return same board without solving anything?

I'm trying to write a simple python Sudoku solver that's implement backtracking which seems to not work at all and doesn't solve anything which I don't Know why. The Puzzle is supposed to have a solution I guess the problem is from the backtracking mechanism but I'm not sure at all Why such behavior could occur.
matric =[
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
def is_possible(y: int, x: int, n: int) -> bool:
# check row and column
for i in range(9):
if matric[y][i] == n:
return False
for i in range(9):
if matric[i][x] == n:
return False
# check box
new_x = x // 3 * 3
new_y = y // 3 * 3
for i in range(3):
for j in range(3):
if matric[new_y + i][new_x + j] == n:
return False
return True
def solve():
global matric
# Find a point
for y in range(9):
for x in range(9):
if matric[y][x] == 0: # found a point to solve
for n in range(1, 10): # Check numbers
if is_possible(y, x, n):
matric[y][x] = n
solve() # Solve Next Point
matric[y][x] = 0 # Back track
return
solve()
for x in matric:
print(x)
Your code always backtracks, even when it has found a solution. There is nothing in your code that says "hey, I found a solution, let's stop looking further". So after all possibilities have been scanned, you end up with a complete backtracked matrix. There is nothing else that this code can do: it will backtrack and set everything to zero. There is no if solved: announce the solution
What you can do
Let solve return a boolean: when it finds that the matrix is full, it should return True. If a recursive call returns True, then don't clear any cell! Instead, immediately return True. That way you will quickly backtrack out of the recursion tree, without changing anything in the matrix. The original caller will then find the matrix with the solution still in tact.
So:
def solve():
global matric
for y in range(9):
for x in range(9):
if matric[y][x] == 0:
for n in range(1, 10):
if is_possible(y, x, n):
matric[y][x] = n
if solve(): # Did we find a solution?
return True # Yes! Tell the caller!
matric[y][x] = 0 # Back track
return False # No way to fill this cell with a valid value
return True # Found no free cell, so this is a solved puzzle!
Be aware that although this algorithm may solve some puzzles, it will spend too much time on harder puzzles. To solve harder puzzles, you would need to add and maintain some more data structures to know which values can still be used in a cell, and which values still need to find a spot in a row, a column, or a block. This will give faster results than when you have to validate a placed value like you do now in is_possible.

Having trouble with the variant of the "Two Sum" coding challenge?

The two problems seeks to find two elements x and y such that x+y=target. This can be implemented using a brute force approach.
for x in arr:
for y in arr:
if x+y==target:
return [x,y]
We are doing some redundant computation in the for loop -- that is we only want to consider combinations of two elements. We can do a N C 2 dual-loop as follows.
for i, x in enumerate(arr):
if y in arr[i+1:]:
if x+y==target:
return [x,y]
And we save a large constant factor of time complexity. Now let's note that inner most loop is a search. We can either use a hash search or a binary search for.
seen = set()
for i, x in enumerate(arr):
if target-x in seen:
y = target-x
return [x,y]
seen.add(x)
Not that seen is only of length of i. And it will only trigger when hit the second number (because it's complement must be in the set).
A variant of this problem is: to find elements that satisfy the following x-y = target. It's a simple variant but it adds a bit of logical complexity to this problem.
My question is: why does the following not work? That is, we're just modifying the previous code?
seen = set()
for i, x in enumerate(arr):
for x-target in seen:
y = x-target
return [x,y]
seen.add(x)
I've asked a friend, however I didn't understand him. He said that subtraction isn't associative. We're exploiting the associative property of addition in the two sum problem to achieve the constant time improvement. But that's all he told me. I don't get it to be honest. I still think my code should work. Can someone tell me why my code doesn't work?
Your algorithm (once the if/for mixup is fixed) still doesn't work because subtraction is not commutative. The algorithm only effectively checks x,y pairs where x comes later in the array than y. That's OK when it's testing x+y = target, since it doesn't matter which order the two values are in. But for x-y = target, the order does matter, since x - y is not the same thing as y - x.
A fix for this would be to check each number in the array to see if it could be either x or y with the other value being one of the earlier values from arr. There needs to be a different check for each, so you probably need two if statements inside the loop:
seen = set()
for n in arr:
if n-target in seen:
x = n
y = n-target
return [x,y]
if n+target in seen:
x = n+target
y = n
return [x,y]
seen.add(x)
Note that I renamed the loop variable to n, since it could be either x or y depending on how the math worked out. It's not strictly necessary to use x and y variables in the bodies of the if statements, you could do those computations directly in the return statement. I also dropped the unneeded enumerate call, since the single-loop versions of the code don't use i at all.

Categories