for programming the Hamming cod in sage ( a compiler based on python) I need to create a matrix in which each column is a binary representation of a number
say Hamming(3) the matrix should look like this
0 0 0 1 1 1 1
0 1 1 0 0 1 1
1 0 1 0 1 0 1
which is the binary represenation of numbers from 1 to 7.
so what i did till now is to convert any given number to it's binary representation:
i made this little function it take two values n and r
and repserent n over r bits
binrep(n,r)
x=n
L=[]
LL=[]
while (n>0):
a=int(float(n%2))
L.append(a)
n=(n-a)/2
while (len(L)<r):
L.append(0)
#print(L)
LL=L[::-1]
return LL
so now i want to collect all the LL i got and make them in one big matrix like the one above
In addition to the other ones, an answer using numpy:
import numpy as np
# we're creating the binary representation for all numbers from 0 to N-1
N = 8
# for that, we need a 1xN matrix of all the numbers
a = np.arange(N, dtype=int)[np.newaxis,:]
# we also need a log2(N)x1 matrix, for the powers of 2 on the numbers.
# floor(log(N)) is the largest component that can make up any number up to N
l = int(np.log2(N))
b = np.arange(l, dtype=int)[::-1,np.newaxis]
# This step is a bit complicated, so I'll explain it below.
print np.array(a & 2**b > 0, dtype=int)
This prints:
[[0 0 0 0 1 1 1 1]
[0 0 1 1 0 0 1 1]
[0 1 0 1 0 1 0 1]]
The line
print np.array(a & 2**b > 0, dtype=int)
does a few things at once. I'll split it up into simpler steps:
# this takes our matrix b and creates a matrix containing the powers of 2
# up to 2^log2(N) == N
# (if N is a power of 2; otherwise, up to the next one below)
powers = 2**b
# now we calculate the bit-wise and (&) for each combination from a and b.
# because a has one row, and b as one column, numpy will automatically
# broadcast all values, so the resulting array has size log2(N)xN.
u = a & powers
# this is almost what we want, but has 4's in the first row,
# 2's in the second row and 1's in the last one.
# one method of getting 1's everywhere is to divide by powers:
print u / powers
# another way is to check where u > 0, which yields an array of bools,
# which we then convert to numbers by turning it into an array of ints.
print np.array(u > 0, dtype=int)
You just have to convert all those binary representations to lists of integers, collect them in a list of lists, and finally transpose that list of lists to get the desired output.
n = 3
binary = []
for i in range(1, 2**n):
s = binrep(i, n)
binary.append(map(int, s))
matrix = zip(*binary)
Or in one line: matrix = zip(*(map(int, binrep(i, n)) for i in range(1, 2**n)))
Result is
[(0, 0, 0, 1, 1, 1, 1),
(0, 1, 1, 0, 0, 1, 1),
(1, 0, 1, 0, 1, 0, 1)]
Also note that there are other ways to convert numbers to binary, e.g. using str.format:
def binrep(n,r):
return "{0:0{1}b}".format(n, r)
Like zoosuck mentioned, I would suggest the bin() function in replacement to your code. To print them in a sequence, assuming that the format is similar:
L = ['10101010', '10101010']
for i in L:
print ' '.join([j for j in i])
In a similar manner, you can append it to a list or a dictionary.
Related
Task: count the number of operations required to make an array's values alternate between even and odd.
Given: items = [6, 5, 9, 7, 3] (Example test case)
Operations we can do: make n number of operations: floor(item/2)
My code
def change(expected):
return 1 if (expected == 0) else 0
def getMinimumOperations(items, expected):
countOp = 0
for i in items:
if (int(i % 2 == 0) != expected):
countOp += 1
expected = change(expected)
return countOp
def minChangeToGetMinOp(items):
minStack = [getMinimumOperations(items, 1), getMinimumOperations(items, 0)]
return min(minStack)
if __name__ == "__main__":
items = [6, 5, 9, 7, 3]
print(minChangeToGetMinOp(items))
ANS: 3
What I'm asking: A good approach to solve this
Taking the comment that the division by 2 can be repeated multiple times on the same input number -- until its parity is as expected (or the number becomes 0 and the odd parity is required), the program would need an inner loop:
def getMinimumOperations(items, expected):
countOp = 0
for i in items:
while i % 2 != expected:
if not i:
return float("inf") # Not possible
i //= 2
countOp += 1
expected = 1 - expected
return countOp
def minChangeToGetMinOp(items):
return min(getMinimumOperations(items, 1), getMinimumOperations(items, 0))
if __name__ == "__main__":
items = [6, 5, 9, 7, 3]
print(minChangeToGetMinOp(items)) # 3
This seems like more of a math/logic problem than a Python problem.
To make a list's elements alternate between odd and even, either all the elements at even indices should be even and the rest odd, or all the elements at even indices should be odd and the rest even.
It appears you're not looking to change the order of elements, but to add or subtract one to make them comply.
So, to make the list comply, either you need to change all even elements at odd indices and all odd elements at even indices, or vice versa.
The answer therefore:
def needed_changes(xs):
c = sum((i + n) % 2 for i, n in enumerate(xs))
return min(c, len(xs) - c)
if __name__ == '__main__':
xs = [6, 5, 9, 7, 3]
print(needed_changes(xs))
Output:
2
The solution adds each element to its index, and then takes the mod 2 of it, so that each element becomes either 1 if the index or the value is odd, or 0 if both are odd, or both are even. As a result, the sum of those 1's will be the number of elements that need to be changed - but if that number is more than half, you could just change the rest of the elements instead, which is what the last lines decides.
Edit: From your comment it became clear that operations allowed are limited and the only operation allowed is x = floor(x / 2). This complicates the issue because this operation only results in an even outcome for every other two numbers. The pattern looks like this:
0 0 # 'even' to start with
1 0 # 'even' after 1 operation
2 1 # even to start with
3 1 # still odd after 1 op, after another 'even' (0)
4 2 # even to start with
5 2 # even after 1 op
6 3 # even to start with
7 3 # still odd after 2 ops, needs 3
8 4 # even to start with
..
So, each 4th number will be both odd, and its floor(x/2) will also be odd. If you apply the operation again, only half of those results will be even, etc.
Another way to look at the problem then: if a number's binary representation ends in a 0, it is even. If you take the floor(x/2) of a number, you're really just performing a "shift right" operation. So, if an number's binary representation has a 0 as the second least significant bit, performing the operation will make it even. And so on.
So, a solution using only that operation:
def needed_changes(xs):
ns = []
for x in xs:
n = 0
while x % 2:
n, x = n + 1, x >> 1
ns.append(n)
return min(sum(ns[0::2]), sum(ns[1::2]))
Or, if you don't like building a whole new list and want the solution to save space:
def needed_changes(xs):
ns = [0, 0]
for i, x in enumerate(xs):
n = 0
while x % 2:
n, x = n + 1, x >> 1
ns[i % 2] += n
return min(ns)
I have a large matrix (like 100.000 x 100.000). The good thing it contains only zeros and ones and mostly zeros (it is already saved as boolean matrix to save some RAM). Now I need to multiply each column of the matrix with all of the other columns. The reason is that I need need to check whether there is as least one row where both columns have a non-zero element (therefore multiplying and summing the resulting vector to check whether it is zero or not). As an example assume we have a matrix
1.column
2.column
3.column
1
0
0
1
1
0
0
0
1
Then I need to compare all columns and check whether there is as least one row where both columns are one. So comparing the first and the second column would return a True since they are both one in the second row. However comparing the first and third column and the second the third column would result in a Falsesince there are no rows with a row where both are one.
Obviously this can be done using a for loop and iterating over all columns. However not in a very satisfying speed. I already tried numba like this:
#njit(parallel=True)
def create_dist_arr(arr: np.array):
n = arr.shape[1]
dist_arr = np.zeros(shape=(n, n)) #, dtype=bool)
for i in prange(arr.shape[1]):
for j in prange(i, arr.shape[1]):
dist_greater_zero = calc_dist_graeter_than_zeros(arr[:, i], arr[:, j])
dist_arr[i][j] = dist_greater_zero
dist_arr[i][j] = dist_greater_zero
return skill_dist_arr
#njit
def calc_dist_graeter_than_zeros(ith_col, jth_col):
return np.sum(np.multiply(ith_col, jth_col)) != 0
zero_arr = np.zeros(shape=(2000, 6000), dtype=bool)
bool_dist_matrix = create_dist_arr(zero_arr)
But despite having 120gb Ram and 32 cores, that gets very slow around 10.000 x 10.000 matrices. Even worse is it when trying scipy.spatial.distance.pdist like this:
from scipy.spatial.distance import pdist
zero_arr = np.zeros(shape=(500, 500), dtype=bool)
bool_dist_matrix = pdist(zero_arr, lambda u, v: np.sum(np.multiply(u, v)) != 0)
Is there maybe some nice and fast workaround using sparse matrices or something else not taking like forever?
Thank you in advance :)
Idk how memory efficient this solution is nor if it will be faster than the other solutions but it is vectorized.
Your idea was to multiply the columns and add the result. which reminded me of matrix multiplication, except its against its own columns. so..
Lets say your matrix is M. If you take the transverse M.T and matrix multiply against itself, M.T # M it will be the same as multiplying each column against the other columns and taking the sum.
import numpy as np
# A random matrix
M = np.array([[1,0,0,0,0,1],
[1,1,0,0,0,1],
[0,1,1,1,0,0]])
bool_dist_matrix = (M.T # M).astype('bool')
np.fill_diagonal(bool_dist_matrix, 0)
"""
[[0 1 0 0 0 1]
[1 0 1 1 0 1]
[0 1 0 1 0 0]
[0 1 1 0 0 0]
[0 0 0 0 0 0]
[1 1 0 0 0 0]]
"""
If your matrix is mainly composed by zeros, then it will be more efficient to work with index:
import numpy as np
# A random matrix
M = np.array([[1,0,0,0,0,1],
[1,1,0,0,0,1],
[0,1,1,1,0,0]])
# Get the index where M == 1
ind = np.where(M)
# Get the unique value and return the count.
uni = np.unique(ind[0], return_counts=True)
# Keep only the column that have at least two 1 in the same row.
col = uni[0][uni[1]>1]
# Create a boolean index.
bol = np.isin(ind[0],col)
# And here we get the "compressed" result:
res = ind[1][bol] #Col number
grp = ind[0][bol] #Group
# res = [0, 5, 0, 1, 5, 1, 2, 3]
# grp = [1, 1, 2, 2, 2, 3, 3, 3]
# So each pair of each group will output a True statement:
# group 1: 0-5
# group 2: 0-1, 0-5, 1-5
# group 3: 1-2, 1-3, 2-3
# For an explicit result you could use itertools. But all the information is
# contained in the res variable.
Noticed that this method will produce some duplicate if, for multiple rows, two column have a common 1 value. But it will be easy to get rid of those duplicate. But since you're working with a 100000x100000 matrix and that not all columns have at least one common 1 value, it is very likely that the percentage of 1 in your matrix is very low, so this method should provide some good result.
I'm not sure what you meant you need to do, but if i understood correctly my code should help. Here's what i tried. It seems to run a little faster. Although that won't be the case if the matrix isn't sparse as you mentioned and i get a symmetric matrix and not an upper triangular one:
import numpy as np
from numba import njit, prange
#njit(parallel=True)
def create_dist_arr(arr: np.array):
n = arr.shape[1]
dist_arr = np.zeros(shape=(n, n)) #, dtype=bool)
for i in prange(arr.shape[1]):
for j in prange(i, arr.shape[1]):
dist_greater_zero = calc_dist_graeter_than_zeros(arr[:, i], arr[:, j])
dist_arr[i][j] = dist_greater_zero
dist_arr[i][j] = dist_greater_zero
return dist_arr
#njit
def calc_dist_graeter_than_zeros(ith_col, jth_col):
return np.sum(np.multiply(ith_col, jth_col)) != 0
def create_dist_arr_sparse(arr: np.array):
n = arr.shape[1]
dist_arr = np.zeros(shape=(n, n)) #, dtype=bool)
rows, cols = np.array(np.where(arr))
same_rows = rows.reshape(1, -1) == rows.reshape(-1, 1)
idx0, idx1 = np.meshgrid(cols, cols)
idx0 = idx0.flatten()[same_rows.flatten()]
idx1 = idx1.flatten()[same_rows.flatten()]
dist_arr[idx0, idx1] = 1
return dist_arr
np.random.seed(1)
k = 1000
zero_arr = np.zeros(shape=(k, k), dtype=bool)
rows, cols = np.random.randint(0, k, (2, k))
zero_arr[rows, cols] = 1
%timeit bool_dist_matrix = create_dist_arr(zero_arr)
%timeit bool_dist_matrix = create_dist_arr_sparse(zero_arr)
output:
1 loop, best of 5: 1.59 s per loop
100 loops, best of 5: 9.8 ms per loop
This question already has answers here:
Convert binary (0|1) numpy to integer or binary-string?
(5 answers)
Closed 1 year ago.
I have task of converting an array with binary numbers into a decimal number.
My array code looks like this:
koo = np.random.randint(2, size=10)
print(koo)
Example of the output is:
[1 0 1 0 0 0 0 0 1 0]
And what I'm supposed to do is to turn it into a string (1010000010), in order to then turn it into a decimal number (642). What could be a way to do this?
For this task I have to create it with the array, I cannot use np.binary_repr()
I have tried solving it with the solution offered here, but when working on it the numbers would be wildly different from what's true (i.e.: 1011111010 was 381 according to the program, while in reality it's 762)
Anybody knows how to solve this problem? Thank you in advance!
At first, convert Numpy array to string by simply appending elements.
Then, using int(), recast the string using base of 2.
koo = np.random.randint(2, size=10)
print(koo)
binaryString = ""
for digit in koo:
binaryString += str(digit)
print(binaryString)
decimalString = int(binaryString, base=2)
print(decimalString)
An example run:
[0 0 1 0 1 0 0 0 0 0]
0010100000
160
you can use a list comprehension to enumerate the digits from end to beginning and then calculate the numbers in base ten, then sum. for example:
np.sum([digit * 2 ** i for i, digit in enumerate(koo[::-1])])
>>> koo = np.random.randint(2, size=10)
>>> koo
array([1, 1, 0, 0, 0, 0, 1, 1, 1, 1])
>>> binary_string = ''.join(koo.astype('str').tolist())
>>> binary_string
'1100001111'
>>> binary_val = int('1100001111', 2)
>>> binary_val
783
This is a diagram of the puzzle I'm solving for:
Where A,B,C,D are four numbers that are either 0 or 1, and alphas are some random constants (could be positive or negative, but ignore the case when they're 0). The goal is to determine the list [A,B,C,D] given a random array of alpha. Here're some rules:
If alpha >0, then the neighboring points have different values. (Ex: if alpha_A = 4.5, then A,B = 01 or 10.
If alpha <0, then the neighboring points have the same value. (Ex: if alpha_B = -4.5, then B,C = 00 or 11.
Making the two adjacent points constant for the highest alpha_i, then start from the 2nd highest absolute value, iterate to the 2nd lowest one. Rule 1 and 2 could be violated only if alpha_i has the minimum absolute value.
Here's the current code I have:
alpha = np.random.normal(0, 10, N_object4)
pa = np.abs(alpha)
N_object4 = 4
num = pa.argsort()[-3:][::-1] # Index of descending order for abs
print(alpha)
print(num)
ABCD = np.zeros(N_object4).tolist()
if alpha[num[0]] > 0:
ABCD[num[0]+1] = 1 # The largest assignment stays constant.
for i in range (1,len(num)): # Iterating from the 2nd largest abs(alpha) to the 2nd smallest.
if i == 3:
num[i+1] = num[0]
elif alpha[num[i]] > 0:
if np.abs(num[i]-num[0]) == 1 or 2:
ABCD[num[i+1]] = 1-ABCD[num[i]]
elif np.abs(num[i]-num[0]) == 3:
ABCD[num[i]] = 1-ABCD[num[0]]
elif alpha[num[i]] < 0:
if np.abs(num[i]-num[0]) == 1 or 2:
**ABCD[num[i+1]] = ABCD[num[i]]**
elif np.abs(num[i]-num[0]) == 3:
ABCD[num[i]] = ABCD[num[0]]
I think I'm still missing something in my code. There's an error in my current version (marked in the line with **):
IndexError: index 3 is out of bounds for axis 0 with size 3
I'm wondering where's my mistake?
Also, an example of the desired output: if
alpha = [12.74921599, -8.01870123, 11.07638142, -3.51723019]
then
num = [0, 2, 1]
The correct list of ABCD should be:
ABCD = [0, 1, 1, 0] (or [1, 0, 0, 1])
My previous version could give me an output, but the list ABCD doesn't look right.
Thanks a lot for reading my question, and I really appreciate your help:)
Looking at your code if found a few smells:
nums is 3 elements long, seems that you want num = pa.argsort()[-4:][::-1]
You also have indexing issues on other places:
if i == 3:
num[i+1] = num[0]
element 4 is not on the array
My personal advice: given the small size of the problem, get rid of numpy and just use python lists.
The other observation (that took me years to learn) is that for small problems, bruteforce is ok.
This is my bruteforce solution, with more time, this can be improved to do backtracking or dynamic programming:
import random
# To make things simpler, I will consider A = 0, and so on
pairs = [
(0, 1),
(1, 2),
(2, 3),
(3, 0),
]
# Ensure no zeros on our list
alphas = [(random.choice([1, -1]) * random.uniform(1, 10), pairs[n]) for n in range(4)]
print(alphas)
# Sort descending in
alphas.sort(reverse=True, key=lambda n: abs(n[0]))
print(alphas[:-1])
def potential_solutions():
"""Generator of potential solutions"""
for n in range(16):
# This just abuses that in binary, numbers from 0 to 15 cover all posible configurations
# I use shift and masking to get each bit and return a list
yield [n >> 3 & 1 , n >> 2 & 1, n >> 1 & 1, n & 1]
def check(solution):
"""Takes a candidate solution and check if is ok"""
for alpha, (right, left) in alphas[:-1]:
if alpha < 0 and solution[right] != solution[left]:
return False
elif alpha > 0 and solution[right] == solution[left]:
return False
return True
# Look for correct solutions
for solution in potential_solutions():
if check(solution):
print(solution)
I am trying to solve a question from HackerRank and when I submit my solution, I get an error stating "Terminated due to timeout".
Please check the code and suggest me how to optimize.
Question:
A left rotation operation on an array of n size shifts each of the array's elements 1 unit to the left. For example, if 2 left rotations are performed on array [1,2,3,4,5], then the array would become [3,4,5,1,2].
Given an array of n integers and a number,d, perform d left rotations on the array. Then print the updated array as a single line of space-separated integers.
Input Format
The first line contains two space-separated integers denoting the respective values of n (the number of integers) and d (the number of left rotations you must perform).
The second line contains space-separated integers describing the respective elements of the array's initial state.
Output Format
Print a single line of n space-separated integers denoting the final state of the array after performing d left rotations.
Sample Input
5 4
1 2 3 4 5
Sample Output
5 1 2 3 4
Explanation
When we perform d = 4 left rotations
Thus, we print the array's final state as a single line of space-separated values, which is 5 1 2 3 4.
My Code:
def array_left_rotation(ar, n, k):
for j in range(k):
temp = ar[0]
for i in range(0,n-1):
ar[i] = ar[i+1]
ar[n-1] = temp
return ar
n, k = map(int, input().strip().split(' '))
a = list(map(int, input().strip().split(' ')))
answer = array_left_rotation(a, n, k);
print(*answer, sep=' ')
Here the best way is not to actually perform the operations yourself. In this case you are manually rotating the list and that is unnecessary computation.
So first, analyze the problem and how it behaves for various outputs. So lets analyze :
Suppose for an Array of 5 elements
array = [1,2,3,4,5]
If you rotate this 2 times, you get :
[3,4,5,1,2]
Now, try the same for rotation with 7 times on the original array. You again get :
[3,4,5,1,2]
Similar trials will see the pattern emerge. ie, for a rotation of k times, it is same as k % n times.
Now that we have that with us, move to the computation part. For that, simply use list slicing to get the rotation, like this :
#n -> number of elements in array
#k -> number of rotations to be performed
#a -> (list) array
def rotate(a,n,k) :
rotations = k % n
new_array = a[rotations:] + a[:rotations]
return new_array
>>> a = [1, 2, 3, 4, 5]
>>> a[2:] + a[:2]
[3, 4, 5, 1, 2]
>>> ' '.join(str(i) for i in (a[2:] + a[:2]))
'3 4 5 1 2'
>>>
>>> def rotate_list(array, d):
... return array[d:] + array[:d]
>>>
>>> ' '.join(str(i) for i in rotate_list([1, 2, 3, 4, 5], 4))
... '5 1 2 3 4'
number_of_elements = int(input("Enter the number of elements to be inserted in array:"))
rotations = int(input("Enter the number of rotations:"))
array = []
for i in range(number_of_elements):
number = int(input("Enter a number:"))
array.append(number)
array = array[rotations:] + array[:rotations]
print(*array, end=' ')