How to overwrite 2-D numpy multi times symmetrically with given index? - python

I'm trying to change values in matrix a with given index matrix d and matrix e.
And the matrix should always be symmetrical.
What I come up with is to overwrite the primal matrix with given index, and try to make it symmetrical, then go for another overwrite, until all the given index matrix have been gone through. It's not efficient.
But I'm stuck with how make it symmetrical.
For example:
a = np.ones([4,4],dtype=np.object) #the primal matrix
d = np.array([[1],
[2],
[0],
[0]]) #the first index matrix
a[np.arange(a.shape[0])[:,None],d] =2 #the element change to 2 with the indexes shown in d matrix
Now the result is:
a = np.array([[1 2 1 1]
[1 1 2 1]
[2 1 1 1]
[2 1 1 1]])
After making it symmetrical (if a[ i ][ j ] was selected in d matrix, a[ j ][ i ] should also be changed to 2, how to do this part).
The expected output should be :
a = np.array([[1 2 2 2]
[2 1 2 1]
[2 2 1 1]
[2 1 1 1]])
Then, for another overwrite again:
e = np.array([[0],[2],[1],[1]])
a[np.arange(a.shape[0])[:,None],e] =3
Now the result is:
a = np.array([[3 2 2 2]
[2 1 3 1]
[2 3 1 1]
[2 3 1 1]])
Make it symmetrical, (I don't know how to do this part) the final output should be : (overwrite the values if they were given 2 or 1 before)
a = np.array([[3 2 2 2]
[2 1 3 3]
[2 3 1 1]
[2 3 1 1]])
What should I do to get symmetrical matrix?
And, is there anyway to change the primal matrix a directly to get the final result? In a more efficient way?
Thanks in advance !!

You can simply switch the first and second indices and apply the change, the result would be symmetrical:
a[np.arange(a.shape[0])[:,None], d] = 2
a[d, np.arange(a.shape[0])[:,None]] = 2
output:
[[1 2 2 2]
[2 1 2 1]
[2 2 1 1]
[2 1 1 1]]
Same with any number of other changes:
a[np.arange(a.shape[0])[:,None], e] = 3
a[e, np.arange(a.shape[0])[:,None]] = 3
output:
[[3 2 2 2]
[2 1 3 3]
[2 3 1 1]
[2 3 1 1]]

Related

Problem with understanding of work of np.argpartition

I have problem with execution of np.argpartition
I have nd.array
example = np.array([[5,6,7,3,4],[1,2,3,7,5],[6,7,4,2,3],[1,2,3,5,9],[2,3,6,1,2,]])
out: [[5 6 7 3 4]
[1 2 3 7 5]
[6 7 4 2 3]
[1 2 3 5 9]
[2 3 6 1 2]]
I can get indices for sorted array by np.argsort
print(np.argsort(example))
out:
[[3 4 0 1 2]
[0 1 2 4 3]
[3 4 2 0 1]
[0 1 2 3 4]
[3 0 4 1 2]]
I want to use np.argsort to economy some time for executing, because I need only 3 sorted element in each row of this array. I use this code to do it:
print(np.argpartition(example, 3, axis=1))
out: [[3 4 0 1 2]
[1 0 2 4 3]
[3 4 2 0 1]
[1 0 2 3 4]
[3 4 0 1 2]]
I expect that the first three indices of each row will match the indices in the sorted array, but this is not the caseю That doesn't work . I don't understand what I did wrong.
np.argpartition(example, k, axis=1) does not return sorted array for first k elements. It only returns indices such that only (k+1)th element is sorted. If you see in your output, only the 4th element matches with argsort()
If you want first three sorted elements, you have to give a list for k parameter
index_array = np.argpartition(example, [0,1,2], axis=1)
print(np.take_along_axis(example,index_array, axis=1)) ##this will give you first 3 sorted elements

Is there a way to permute a subset of a matrix?

I'm working on a way to find the lowest 1-Norm of a given Matrix using a permutation of its rows. The problem is that the permutation can't be fully random. There are 4 subsets of rows in the Matrix having a special parameter. I want to permute just the rows having this one parameter and keeping those on the same spot.
Ex. The first column defines the type of row.
A = [
1, val_11, val_12, ... #1. Row
2, val_21, val_22, ... #2. Row
2, val_31, val_32, ... #3. Row
2, val_41, val_42, ... #4. Row
1, val_51, val_52, ... #5. Row
]
So in this example I want to permute the 1. and 5. Row AND permute the 2., 3. and 4. Row keeping the Types like [1;2;2;2;1] in place.
You just have to carefully define your permutations. Fancy indexing will then do the job :
Example :
from numpy.random import randint
M0 = randint(10,size=(5,5))
after=[4,2,3,1,0]
M0 = M[after]
print(M0)
print(M)
[[4 9 3 0 0]
[3 1 7 6 0]
[6 6 5 0 9]
[0 4 7 1 3]
[0 0 1 0 6]]
[[0 0 1 0 6]
[6 6 5 0 9]
[0 4 7 1 3]
[3 1 7 6 0]
[4 9 3 0 0]]

Python: get all the possible combinations for allocating x apples to y baskets subject to constraint

Suppose we have x apples and y baskets, we want to allocate all the apples to baskets such that each basket at most get z apples. How to write Python codes to get all possible combinations.
For small number of y, I can just loop with respect to y as follows (x=5, y=3, z=2).
all_chances = np.zeros((0,3))
for a in range(3):
for b in range(3):
for c in range(3):
if a+b+c == 5:
all_chances = np.vstack((all_chances, np.array([a,b,c])))
Basically, all_chances are
array([[1., 2., 2.],
[2., 1., 2.],
[2., 2., 1.]])
My question is: what if y is a large number, like x = 30, y = 26, z=2? Do I need to loop 26 times?
I messed around with your question... tried implementing a sort of tree-based approach bc I thought it'd be clever, but my laptop chokes on it. I was curious how many permutations we're looking for with these large numbers anyway, and changed the problem (for myself) to simply counting the permutations to see if it was even doable on a light-weight laptop.
I get 154,135,675,070 unique permutations.
To get started... I messed around with itertools, and permutations took forever with lists of length 26. So... to remind myself of the long-forgotten formula to at least count distinct permutations, I found this... https://socratic.org/questions/how-many-distinct-permutations-can-be-made-from-the-letters-of-the-word-infinity
With that I ran the following to get a count. It runs in under a second.
from numpy import prod
from math import factorial
import itertools
# number of unique permutations
def count_distinct_permutations(tup):
value_counts = [len(list(grp)) for _, grp in itertools.groupby(tup)]
return factorial(sum(value_counts)) / prod([float(factorial(x)) for x in value_counts])
# starting values
x = 30 # apples
y = 26 # baskets
z = 3 # max per basket
# count possible results
result = 0
for combos in itertools.combinations_with_replacement(range(z), y):
if sum(combos) == x:
result += count_distinct_permutations(combos)
Now... this obviously does NOT answer your specific question. Honestly I couldn't hold the result you're looking for in memory anyway. But... you can make some inferences with this... with your chosen values, there's only 12 combinations of values, but between 15k and 50 million permutations of each combination.
You could look at each combination... in the count_distinct_permutations() function, itertools.groupby feeds you how many of each number from (0,1,2) is in the combination, and you could work with each of those twelve results to infer some stuff. Not sure what, but I also am not quite sure what to do with 154 billion lists of length 26. :)
Hope there was something useful here, even if it didn't answer your exact question. Good luck!
Here is a method based on Young diagrams. For example, 4 baskets, 6 eggs, max 3 eggs per basket. If we order the baskets by how full they are we get Young diagrams.
x x x x x x x x x x x x x x x x
x x x x x x x x x x
x x x x
The code below enumerates all possible Young diagrams and for each enumerates all possible permutations.
The same logic can also be used to count.
from itertools import product, combinations
from functools import lru_cache
import numpy as np
def enum_ord_part(h, w, n, o=0):
if h == 1:
d = n
for idx in combinations(range(w), d):
idx = np.array(idx, int)
out = np.full(w, o)
out[idx] = o+1
yield out
else:
for d in range((n-1)//h+1, min(w, n) + 1):
for idx, higher in product(combinations(range(w), d),
enum_ord_part(h-1, d, n-d, o+1)):
idx = np.array(idx)
out = np.full(w, o)
out[idx] = higher
yield out
def bc(n, k):
if 2*k > n:
k = n-k
return np.prod(np.arange(n-k+1, n+1, dtype='O')) // np.prod(np.arange(1, k+1, dtype='O'))
#lru_cache(None)
def count_ord_part(h, w, n):
if h == 1:
return bc(w, n)
else:
return sum(bc(w, d) * count_ord_part(h-1, d, n-d)
for d in range((n-1)//h+1, min(w, n) + 1))
Few examples:
>>> for i, l in enumerate(enum_ord_part(3, 4, 6), 1):
... print(l, end=' ' if i % 8 else '\n')
...
[3 3 0 0] [3 0 3 0] [3 0 0 3] [0 3 3 0] [0 3 0 3] [0 0 3 3] [3 2 1 0] [2 3 1 0]
[3 1 2 0] [2 1 3 0] [1 3 2 0] [1 2 3 0] [2 2 2 0] [3 2 0 1] [2 3 0 1] [3 1 0 2]
[2 1 0 3] [1 3 0 2] [1 2 0 3] [2 2 0 2] [3 0 2 1] [2 0 3 1] [3 0 1 2] [2 0 1 3]
[1 0 3 2] [1 0 2 3] [2 0 2 2] [0 3 2 1] [0 2 3 1] [0 3 1 2] [0 2 1 3] [0 1 3 2]
[0 1 2 3] [0 2 2 2] [3 1 1 1] [1 3 1 1] [1 1 3 1] [1 1 1 3] [2 2 1 1] [2 1 2 1]
[2 1 1 2] [1 2 2 1] [1 2 1 2] [1 1 2 2]
>>>
>>> print(f'{count_ord_part(2, 26, 30):,}')
154,135,675,070
>>> print(f'{count_ord_part(50, 30, 1000):,}')
63,731,848,167,716,295,344,627,252,024,129,873,636,437,590,711

Delimiting a region of a numpy matrix

I have a 560x560 numpy matrix, which I want to convert to a 28x28 one.
Therefore, I want to subdivide it into regions with size 16x16, calculate the mean of each such regions and put that value in a new matrix.
Now I have:
import numpy as np
oldMat = ... #I load the 560x560 matrix
newMat = np.zeros((28,28)) #Initializes the new matrix of size 28x28
for i in range(0,560, 16):
for j in range(0,560, 16): #Loops over the top left corner of each region
sum = 0
for di in range(16):
for dj in range(16): #Loops over the indices of the elements in each region
sum += oldMat[i+di, j+dj]
mean = sum/256 #Calculates the mean of the elements of each region
newMat[i][j] = mean
Is there a faster way to do this? (I'm sure there is.)
If you simply want to reshape your matrix from 2D --> 4D, then you can use np.reshape():
import numpy as np
np.random.seed(0)
data = np.random.randint(0,5,size=(6,6))
Yields:
[[4 0 3 3 3 1]
[3 2 4 0 0 4]
[2 1 0 1 1 0]
[1 4 3 0 3 0]
[2 3 0 1 3 3]
[3 0 1 1 1 0]]
Then reshape:
data.reshape((3,3,2,2))
Returns:
[[[[4 0]
[3 3]]
[[3 1]
[3 2]]
[[4 0]
[0 4]]]
[[[2 1]
[0 1]]
[[1 0]
[1 4]]
[[3 0]
[3 0]]]

How to create graph dictionary for traversal based on permutation and combination in python

I am facing some issues in putting things together while implementing in python (Just a beginner). I want to create set of data array on permutation and combination based on another array vector which will only be based on three types of numbers -1, 0, 1. It can be in any order and in any number. It can be [-1 1 0 0 -1] or [-1 -1 0 0] or [-1 1] etc.
Suppose I have data array of 4 values [a b c d] = [5 4 0 0] based on model chemical reaction a + b -> c + d then according to this reaction changing array vector be created as v = [-1 -1 1 1], as a and b are producing c and d until a or b exhausted and reach 0. Now when we apply this array vector on [a b c d], we will get new array's like [4 3 1 1], [3 2 2 2], [2 1 3 3], [1 0 4 4]... now we cannot generate new array further as v cannot be applied on [1 0 4 4] because b is 0. This is a simple case. I have this simple code running to create next array but not in loops to create further array's :: [3 2 0 2], [2 1 0 3], [1 0 0 4].
class SumList(object):
def __init__(self, this_list):
self.mylist = this_list
def __add__(self, other):
new_list = []
zipped_list = zip(self.mylist, other.mylist)
for item in zipped_list:
new_list.append(item[0] + item[1])
return SumList(new_list)
def __repr__(self):
return str(self.mylist)
list1 = SumList([5, 4, 0, 0])
list2 = SumList([-1, -1, 1, 1])
sum = list1 + list2
print(sum)
This is what I want to achieve finally:: If I have multiple reactions and multiple vector array's, like
a + b -> c
c -> a + b
c -> b + d
v1 = [-1 -1 1 0],
v2 = [1 1 -1 0],
v3 = [0 1 -1 1]
Where, initial quantity of [a b c d] = [5 4 0 0] and want to apply v1, v2 and v3 on [a b c d] to create new data array's, like...
When v1 is applied on [a b c d] it will give
[4 3 1 0], [3 2 2 0], [2 1 3 0], [1 0 4 0]
When v2 is applied on [a b c d] it will check that v2 cannot be applied on [5 4 0 0], as number of total molecules in the system is fixed (a=5, b=4) at max and cannot be increased to a=6, b=5 respectively, so in this case v2 cannot give us [6 5 -1 0].. so now v2 will be applied on [4 3 1 0] which is a 1st new array in case of v1...so we will get [5 4 0 0]. Now v2 will be applied on 2nd new array of v1 i.e. [3 2 2 0] which gives us [4 3 1 0].... now v2 applied on 3rd ([2 1 3 0]) and 5th ([1 0 4 0]) new array of v1 which will give us [3 2 2 0] and [2 1 3 0] respectively. So final v2 new array list will be
[5 4 0 0], [4 3 1 0], [3 2 2 0], [2 1 3 0]
When v3 is applied on [a b c d] to it will again check if v3 can be applied on [5 4 0 0] or not. It clearly shows that we cannot apply v3 on [5 4 0 0] as it will give [5 5 -1 -1] which is not acceptable. So now, we need to check if we can apply v3 on new array's of v2 and v3 and have the new array list for v3.
v3 can be applied on [4 3 1 0] one time giving us new array [4 4 0 1].
v3 can be applied on [3 2 2 0] two times giving us 2 new array's [3 3 1 1] and [3 4 0 2]... [Note: here b=4 so we cannot apply v3 further as b cannot exceed its initial quantity 4.... and c will be -1 which is not valid].
Once all the new array's are generated by applying v1, v2 and v3 on every possible new array, I need to take union and only print unique array's..!! As you can see some of array's are repeated in case of v1 and v2.
In simple terms, I want to apply v1, v2 and v3 on [5 4 0 0] and on all possible new array's, apply the checks where possible and take the union in the last and print it. I hope I have explained my problem in a simple way. Presently I trying to modify
from itertools import permutations
print sorted(list(set(list(permutations('5400', 4)))))
Any guidance on how to modify the Class SumList code is appreciated. Thank you for reading.

Categories

Resources