python: copy values of big array in smaller arrays - python-3.x

I have a problem,
where I would like to copy values of X a ( n x n ) array into smaller array A, B , C, D
here is my current code.
X = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
n = len(X)
n_by_2 = n // 2
A = [[]]
B = [[]]
C = [[]]
D = [[]]
"""
X = [
A<-- B<--
[1,2, | 3,4],
[5,6, | 7,8],
-------|-------
D<-- | C<--
[9,10, | 11,12],
[13,14,| 15,16]
]
"""
for i in range(len(X)):
for j in range(len(X[i])):
if (i >= 0 and i < n_by_2) and (j >= 0 and j < n_by_2):
#copy 1st quadrent values to A
#A[i][j] = X[i][j]
if (i >= 0 and i < n_by_2) and (j >= n_by_2 and j < n):
#copy 2nd quadrent values to B
#B[i][j] = X[i][j]
if (i >= n_by_2 and i < n) and (j >= 0 and j < n_by_2):
#copy 3rd quadrent values to C
#C[i][j] = X[i][j]
if (i >= n_by_2 and i < n) and (j >= n_by_2 and j < n):
#copy 4th quadrent values to D
#D[i][j] = X[i][j]

Be careful that you cannot add a new item x to an empty list l by doing.
l[0] = x. This only works if the list already has a length greater than 0. In that situation, you can use the append method instead.
For your problem, this code will do the job:
X = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
n = len(X)
n_by_2 = n // 2
A = []
B = []
C = []
D = []
for i in range(n_by_2):
A.append(X[i][:n_by_2])
B.append(X[i][n_by_2-1:-1])
for i in range(n_by_2):
C.append(X[i + n_by_2][:n_by_2])
D.append(X[i + n_by_2][n_by_2-1:-1])
print(A)
print(B)
print(C)
print(D)

Related

Why doesn't assigning new values to a numpy array work?

I have the following code. The beggining is quite long, but only serves to generate data. The problem happens with a few lines at the end.
##### Import packages
import numpy as np
import scipy.linalg as la
##### Initial conditions
N = 5
lamda = 7
mu = 2
a = 0.5
r = - np.log(a).copy()
St_Sp = np.arange(- N, N + 1)
Card = St_Sp.shape[0]
##### Define infintesimal generator
def LL(x, y):
if x == N or x == - N: re = 0
elif x - y == - 1: re = lamda
elif x - y == 1: re = mu
elif x - y == 0: re = - (mu + lamda)
else: re = 0
return re
def L(x):
return - LL(x, x)
##### Define function Phi
def Phi(x): return max(x, 0)
Phi = np.vectorize(Phi)
##### Define vector b
b = Phi(St_Sp).copy()
##### Define function Psi
def Psi(x): return L(x) / (L(x) + r)
Psi = np.vectorize(Psi)
##### Generate a Boolean vector whose all elements are False
d = np.array([0] * Card).astype(bool)
##### Define matrix A
A = np.zeros((Card, Card))
for i in range(Card):
for j in range(Card):
if (i != j) & (L(St_Sp[i]) != 0):
A[i, j] = LL(St_Sp[i], St_Sp[j]) / L(St_Sp[i])
elif (i != j) & (L(St_Sp[i]) == 0):
A[i, j] = 0
elif (i == j) & (Psi(St_Sp[i]) != 0):
A[i, j] = - 1 / Psi(St_Sp[i])
else: A[i, j] = 1
##### Row names of A
rows = np.arange(0, Card)
##### Define matrix B
B = np.zeros((Card, Card))
for i in range(Card):
for j in range(Card):
if i != j:
B[i, j] = LL(St_Sp[i], St_Sp[j])
else: B[i, j] = LL(St_Sp[i], St_Sp[j]) - r
##### Generate I_0
I = [np.array([1] * Card).astype(bool), d.copy()]
Z = b.copy()
index0 = np.matmul(B, Z) <= 0
index1 = ~ index0
##### Generate I_1
I = [index0, index1]
Z = b.copy()
if np.sum(I[1]) > 0:
order = np.concatenate((rows[I[1]], rows[~ I[1]]))
A1 = A[np.ix_(rows[I[1]], order)]
A2 = la.lu(A1)[2]
p = np.atleast_2d(A1).shape[0]
B1 = A2[:, range(p)]
B2 = - np.matmul(A2[:, p:], Z[I[0]])
print('Before being assigned new values, Z is \n', Z)
print('\n The index I[1] of elements of Z to be change \n', I[1])
M = la.solve_triangular(B1, B2, lower = False)
print('\n The values to be assigned to Z[I[1]] is \n', M)
Z[I[1]] = M
print('\n After being assigned new values, Z is \n', Z)
with result
Before being assigned new values, Z is
[0 0 0 0 0 0 1 2 3 4 5]
The index I[1] of elements of Z to be change
[False False False False False True True True True True False]
The values to be assigned to Z[I[1]] is
[2.08686055 2.88974949 3.40529229 3.88978577 4.41338306]
After being assigned new values, Z is
[0 0 0 0 0 2 2 3 3 4 5]
It's very weird to me that the command Z[I[1]] = M does not assign new values from M to the postion of Z indexed by I[1]. Could you please elaborate on why this problem arises and how to resolve it?
The datatype of your array Z is int, to the values are typecasted by python automatically, resulting in the interger values of int([2.08686055 2.88974949 3.40529229 3.88978577 4.41338306]) = [2 2 3 3 4 5].
If you want to change that behavour, you just need to add a line to change the type of your original array:
Z = Z.astype(float)

Count the number of possible ways to solve an equation

This question was asked in a challenge in HackerEarth:
Mark is solving an interesting question. He needs to find out number
of distinct ways such that
(i + 2*j+ k) % (x + y + 2*z) = 0, where 1 <= i,j,k,x,y,z <= N
Help him find it.
Constraints:
1<= T<= 10
1<=N<= 1000
Input Format:
First line contains T, the number of test cases. Each of the test case
contains a single integer,N in a separate line.
Output Format:
For each test case , output in a separate line, the number of distinct
ways.
Sample Input
2
1
2
Sample Output
1
15
Explanation
In the first case, the only possible way is i = j = k = x =y = z = 1
I am not getting any way how to solve this problem, I have tried one and I know it's not even close to the question.
import random
def CountWays (N):
# Write your code here
i = random.uniform(1,N)
j = random.uniform(1,N)
k = random.uniform(1,N)
x = random.uniform(1,N)
y = random.uniform(1,N)
z = random.uniform(1,N)
d = 0
for i in range(N):
if (i+2*j+k)%(x+y+2*z)==0:
d += 1
return d
T = int(input())
for _ in range(T):
N = int(input())
out_ = CountWays(N)
print (out_)
My Output
0
0
Instead it should give the output
1
15
The value of the numerator (num) can range from 4 to 4N. The value of the denominator (dom) can range from 4 to num. You can split your problem into two smaller problems: 1) How many values of the denominator is a given value of the numerator divisible by? 2) How many ways can a given denominator and numerator be constructed?
To answer 1) we can simply loop through all the possible values of the numerator, then loop over all the values of the denominator where numerator % denominator == 0. To answer 2) we can find all the partitions of the numerator and denominator that satisfies the equality and constraints. The number of ways to construct a given numerator and denominator will be the product of the number of partitions of each.
import itertools
def divisible_numbers(n):
"""
Get all numbers with which n is divisible.
"""
for i in range(1,n+1):
if n % i == 0:
yield i
if i >= n:
break
def get_partitions(n):
"""
Generate ALL ways n can be partitioned into 3 integers.
Modified from http://code.activestate.com/recipes/218332-generator-for-integer-partitions/#c9
"""
a = [1]*n
y = -1
v = n
while v > 0:
v -= 1
x = a[v] + 1
while y >= 2 * x:
a[v] = x
y -= x
v += 1
w = v + 1
while x <= y:
a[v] = x
a[w] = y
if w == 2:
yield a[:w + 1]
x += 1
y -= 1
a[v] = x + y
y = a[v] - 1
if w == 3:
yield a[:w]
def get_number_of_valid_partitions(num, N):
"""
Get number of valid partitions of num, given that
num = i + j + 2k, and that 1<=i,j,k<=N
"""
n = 0
for partition in get_partitions(num):
# This can be done a bit more cleverly, but makes
# the code extremely complicated to read, so
# instead we just brute force the 6 combinations,
# ignoring non-unique permutations using a set
for i,j,k in set(itertools.permutations(partition)):
if i <= N and j <= N and k <= 2*N and k % 2 == 0:
n += 1
return n
def get_number_of_combinations(N):
"""
Get number of ways the equality can be solved under the given constraints
"""
out = 0
# Create a dictionary of number of valid partitions
# for all numerator values we can encounter
n_valid_partitions = {i: get_number_of_valid_partitions(i, N) for i in range(1,4*N+1)}
for numerator in range(4,4*N+1):
numerator_permutations = n_valid_partitions[numerator]
for denominator in divisible_numbers(numerator):
denominator_permutations = n_valid_partitions[denominator]
if denominator < 4:
continue
out += numerator_permutations * denominator_permutations
return out
N = 2
out = get_number_of_combinations(N)
print(out)
The scaling of the code right now is very poor due to the way the get_partitions and the get_number_of_valid_partitions functions interact.
EDIT
The following code is much faster. There's a small improvement to divisible_numbers, but the main speedup lies in get_number_of_valid_partitions not creating a needless amount of temporary lists as it has now been joined with get_partitions in a single function. Other big speedups comes from using numba. The code of get_number_of_valid_partitions is all but unreadable now, so I've added a much simpler but slightly slower version named get_number_of_valid_partitions_simple so you can understand what is going on in the complicated function.
import numba
#numba.njit
def divisible_numbers(n):
"""
Get all numbers with which n is divisible.
Modified fromĀ·
"""
# We can save some time by only looking at
# values up to n/2
for i in range(4,n//2+1):
if n % i == 0:
yield i
yield n
def get_number_of_combinations(N):
"""
Get number of ways the equality can be solved under the given constraints
"""
out = 0
# Create a dictionary of number of valid partitions
# for all numerator values we can encounter
n_valid_partitions = {i: get_number_of_valid_partitions(i, N) for i in range(4,4*N+1)}
for numerator in range(4,4*N+1):
numerator_permutations = n_valid_partitions[numerator]
for denominator in divisible_numbers(numerator):
if denominator < 4:
continue
denominator_permutations = n_valid_partitions[denominator]
out += numerator_permutations * denominator_permutations
return out
#numba.njit
def get_number_of_valid_partitions(num, N):
"""
Get number of valid partitions of num, given that
num = i + j + 2l, and that 1<=i,j,l<=N.
"""
count = 0
# In the following, k = 2*l
#There's different cases for i,j,k that we can treat separately
# to give some speedup due to symmetry.
#i,j can be even or odd. k <= N or N < k <= 2N.
# Some combinations only possible if num is even/odd
# num is even
if num % 2 == 0:
# i,j odd, k <= 2N
k_min = max(2, num - 2 * (N - (N + 1) % 2))
k_max = min(2 * N, num - 2)
for k in range(k_min, k_max + 1, 2):
# only look at i<=j
i_min = max(1, num - k - N + (N + 1) % 2)
i_max = min(N, (num - k)//2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
# if i == j, only one permutations
# otherwise two due to symmetry
if i == j:
count += 1
else:
count += 2
# i,j even, k <= N
# only look at k<=i<=j
k_min = max(2, num - 2 * (N - N % 2))
k_max = min(N, num // 3)
for k in range(k_min, k_max + 1, 2):
i_min = max(k, num - k - N + N % 2)
i_max = min(N, (num - k) // 2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == j == k:
# if i == j == k, only one permutation
count += 1
elif i == j or i == k or j == k:
# if only two of i,j,k are the same there are 3 permutations
count += 3
else:
# if all differ, there are six permutations
count += 6
# i,j even, N < k <= 2N
k_min = max(N + 1 + (N + 1) % 2, num - 2 * N)
k_max = min(2 * N, num - 4)
for k in range(k_min, k_max + 1, 2):
# only look for i<=j
i_min = max(2, num - k - N + 1 - (N + 1) % 2)
i_max = min(N, (num - k) // 2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == j:
# if i == j, only one permutation
count += 1
else:
# if all differ, there are two permutations
count += 2
# num is odd
else:
# one of i,j is even, the other is odd. k <= N
# We assume that j is odd, k<=i and correct the symmetry in the counts
k_min = max(2, num - 2 * N + 1)
k_max = min(N, (num - 1) // 2)
for k in range(k_min, k_max + 1, 2):
i_min = max(k, num - k - N + 1 - N % 2)
i_max = min(N, num - k - 1)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == k:
# if i == j, two permutations
count += 2
else:
# if i and k differ, there are four permutations
count += 4
# one of i,j is even, the other is odd. N < k <= 2N
# We assume that j is odd and correct the symmetry in the counts
k_min = max(N + 1 + (N + 1) % 2, num - 2 * N + 1)
k_max = min(2 * N, num - 3)
for k in range(k_min, k_max + 1, 2):
i_min = max(2, num - k - N + (N + 1) % 2)
i_max = min(N, num - k - 1)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
count += 2
return count
#numba.njit
def get_number_of_valid_partitions_simple(num, N):
"""
Simpler but slower version of 'get_number_of_valid_partitions'
"""
count = 0
for k in range(2, 2 * N + 1, 2):
for i in range(1, N + 1):
j = num - i - k
if 1 <= j <= N:
count += 1
return count
if __name__ == "__main__":
N = int(sys.argv[1])
out = get_number_of_combinations(N)
print(out)
The current issue with your code is that you've picked random numbers once, then calculate the same equation N times.
I assume you wanted to generate 1..N for each individual variable, which would require 6 nested loops from 1..N, for each variable
Now, that's the brute force solution, which probably fails on large N values, so as I commented, there's some trick to find the multiples of the right side of the modulo, then check if the left side portion is contained in that list. That would only require two triple nested lists, I think
(i + 2*j+ k) % (x + y + 2*z) = 0, where 1 <= i,j,k,x,y,z <= N
(2*j + i + k) is a multiple of (2*z + x + y)
N = 2
min(2*j + i + k) = 4
max(2*j + i + k) = 8
ways to make 4: 1 * 1 = 1
ways to make 5: 2 * 2 = 4
ways to make 6: 2 * 2 = 4
ways to make 7: 2 * 2 = 4
ways to make 8: 1 * 1 = 1
Total = 14
But 8 is a multiple of 4 so we add one more instance for a total of 15.

Where should I put the count in this tim sort algorithm, to accurately compare runtime to other algorithms

I've written a Timsort sorting algorithm for a computer science class, I would like to be able to compare the runtime to other similar algorithms, such as merge sort for instance. However, I am not sure where I should put the count (ie: count +=1)within the code to have an accurate run time. Any help would be much appreciated.
RUN = 32
def insertion_sort(arr, left, right):
for i in range(left + 1, right + 1):
temp = arr[i]
j = i - 1
while (arr[j] > temp and j >= left):
arr[j + 1] = arr[j]
arr[j] = temp
j -= 1
def merge(arr, left, right, count):
c = 0
index = count
length = len(left) + len(right)
while left and right:
if left[0] < right[0]:
arr[index] = left.pop(0)
c += 1
index += 1
else:
arr[index] = right.pop(0)
c += 1
index += 1
if len(left) == 0:
while c < length:
arr[index] = right.pop(0)
c += 1
index += 1
elif len(right) == 0:
while c < length:
arr[index] = left.pop(0)
c += 1
index += 1
def tim_sort(arr):
n = len(arr)
for i in range(0, n, RUN):
insertion_sort(arr, i, min((i + (RUN - 1)), (n - 1)))
size = RUN
while size < n:
for left in range(0, n, 2 * size):
if (left + size > n):
merge(arr, arr[left:n], [], left)
else:
left_sub_arr = arr[left:(left + size)]
right_sub_arr = arr[(left + size):min((left + 2 * size), n)]
merge(arr, left_sub_arr, right_sub_arr, left)
size *= 2
return arr

How to compare the elements of a nested list?

I have some kind of matrix:
[[1,2,3],[1,2,3],[0,2,1],[1,2,3]] and I would like to be able to determine how many times I have the sequence 1,2,3 diagonally, vertically and horizontally but I have problems of index out of range for the last two loops. Thank you in advance for your answers!!
lista = [[1,2,3],[1,2,3],[0,2,1],[1,2,3]]
compteur_horizontal = 0
for i in range(len(lista)):
for c in range(len(lista[i])-2):
if lista[i][c] == 1 and lista[i][c+1] == 2 and lista[i][c+2] == 3:
compteur_horizontal += 1
print("ok")
compteur_vertical = 0
for c in range(len(lista)):
for j in range(len(lista[c])):
print(lista[j][c])
compteur_diagonale = 0
for j in range(len(lista)):
print(lista[i][i])
For the first counter, I would like it to be 3 since we have 3 times the sequence 1,2,3 horizontally. For the second counter, I would like it to be 0 because vertically there is no 1,2,3 sequence. And I'm waiting for a counter with 0 also since there's no 1,2,3 sequence in diagonal
Your code will not work even if you correct the current error. You need to change j and c in the second loop to resolve the error.
For horizontal and vertical here's the code. I'll add how to count diagonal ones later.
#lista = [[1, 2, 3],[1, 2, 3],[0, 2, 1],[1, 2, 3]]
lista = [[1,2,2],
[1,2,4],
[4,2,3],
[5,6,3]]
ptrn = [1, 2, 3]
# returns True is lst (1d array) has ptrn (1d array).
# e.g. lst[1,2,4,6,1,2,3,7], ptrn=[1,2,3] return True
# e.g. lst[1,2,4,6,1,4,3,7], ptrn=[1,2,3] return False
def is_pattern_in_a_list(lst, ptrn):
if ptrn[0] in lst:
idx = lst.index(ptrn[0])
for i in range(1, len(ptrn)):
if idx + i < len(lst):
if ptrn[i] != lst[idx+i]:
return False
else:
return False
return True
else:
return False
# counting horizontal occurances
count_h = 0
for row in lista:
if is_pattern_in_a_list(row, ptrn):
count_h += 1
# counting vertical occurances
# we first transpose the 2d array and use the same
# method of counting horizontal occurances.
def transpose_2d_array(a):
return [[a[j][i] for j in range(len(a))] for i in range(len(a[0]))]
lista_transpose = transpose_2d_array(lista)
count_v = 0
for row in lista_transpose:
if is_pattern_in_a_list(row, ptrn):
count_v += 1
# for diagonal occurances first we need to extract the diagonals
# with len >= len(ptrn).
# diagonals for the upper right triangle of the matrix:
count_d = 0
for i in range(len(lista[0])):
diag = []
j = 0
k = i
while j < len(lista)-i and k < len(lista[0]):
diag.append(lista[j][k])
j += 1
k += 1
if is_pattern_in_a_list(diag, ptrn):
count_d += 1
# diagonals for the lower left triangle of the matrix
i = len(lista) - 1
while i >= 1:
j = i
k = 0
diag = []
while j < len(lista) and k <= len(lista)+1-i:
diag.append(lista[j][k])
j += 1
k += 1
i -= 1
if is_pattern_in_a_list(diag, ptrn):
count_d += 1
print(diag)
print("Horizontal %d" % count_h)
print("Vertical %d" % count_v)
print("Diagonal %d" % count_d)

List rotation to the left in Python 3

I'm trying to create a list (b) that is list (a) rotating a's members k times to the left. I came up with this on Python 3:
n = 5
k = 4
a = [1,2,3,4,5]
b = []
for i in a:
if (i + k) <= (n - 1):
b.append(a[i+k])
elif (i+k-n) < (n-1):
b.append(a[i+k-n])
print(b)
But for some reason, it doesn't work since when I tell print(b) it returns a list that is exactly like list a
What am I missing here?
A simple solution:
k = k % len(a) #we don't care about shifting x*len(a) times since it does not have any effect
b = a[k:] + a[:k]
Thanks to #RemcoGerlich for helping me see my mistake! Here's how I quickly fixed my code:
n = 5
k = 4
a = [1,2,3,4,5]
b = []
i = 0
while (i < n):
if (i + k) <= (n - 1):
b.append(a[i+k])
elif (i+k-n) < (n-1):
b.append(a[i+k-n])
i = i+1
print(b)

Resources