python row dividing with one element - python-3.x

I am reading 'Computational Physics -Mark Newman' book.
The following is one of its example.
from numpy import *
A = array([
[2, 1, 4, 1],
[3, 4, -1, -1],
[1, -4, 1, 5],
[2, -2, 1, 3]
])
v = array([-4, 3, 9, 7], float)
N = len(v)
for m in range(N):
div = A[m,m]
A[m,:] /= div <-----------(not working)
v[m] /= div
...
It is one part of back-substitution implementation.
But while dividing div(diagonal element of row in matrix), it shows error.
"A[m,:] /= div
TypeError: No loop matching the specified signature and casting was found for ufunc true_divide"
What made this error? How can i fix it?

This should fix it:
import numpy as np
A = np.array([
[2, 1, 4, 1],
[3, 4, -1, -1],
[1, -4, 1, 5],
[2, -2, 1, 3]
], dtype=np.float)
v = np.array([-4, 3, 9, 7], float)
N = len(v)
for m in range(N):
div = A[m, m]
A[m, :] /= div
v[m] /= div
Or if you really want integer division:
for m in range(N):
div = A[m, m]
A[m, :] = A[m, :] / div
v[m] /= div
The issue is that in Python 3, / does the true division, so it convert the results to float, and when you do A[m, :] /= div you are trying to assign a float result to A which is of type integer. You can find more information on this, here
As a side-note is generally better not to use:
from numpy import *

Related

Stacking all the rolled vectors of a given vector in PyTorch

Given a 1d vecotr x of size n, how can we construct an n-by-n matrix X consisting of all the rolled vectors of x in PyTorch?
For example
x = torch.tensor([1,2,3,4])
The expected output is
tensor([[1, 2, 3, 4],
[2, 3, 4, 1],
[3, 4, 1, 2],
[4, 1, 2, 3]])
Is there any better way than this?
N = x.shape[0]
A = torch.zeros(N, N)
for i in range(N):
A[i] = torch.roll(x, -i)

torch matrix equaity sum operation

I want to do an operation similar to matrix multiplication, except instead of multiplying I want to check equality. The effect that I want to achieve is similar to the following:
a = torch.Tensor([[1, 2, 3], [4, 5, 6]]).to(torch.uint8)
b = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).to(torch.uint8)
result = [[sum(a[i] == b [j]) for j in range(len(b))] for i in range(len(a))]
Is there a way that I can use einsum, or any other function in pytorch to achieve the above efficiently?
You can use torch.repeat and torch.repeat_interleave:
a = torch.Tensor([[1, 2, 3], [4, 5, 6]])
b = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mask = a.repeat_interleave(3, dim=0) == b.repeat((2, 1))
torch.sum(mask, axis=1).reshape(a.shape)
# output
tensor([[3, 0, 0],
[0, 3, 0]])
You can make use of the broadcasting to do the same, for instance with
result = (a[:, None, :] == b[None, :, :]).sum(dim=2)
Here None just introduces a dummy dimensions - alternatively you can use the less visual .unsqueeze() instead.
matrix multiplication is ij,jk->ik in einsum notation, all of these operations are equivalent with varying levels of verbosity:
a # b
torch.einsum("ij,jk", a, b)
torch.einsum("ij,jk->ik", a, b)
(a[:,:,None] * b[None,:,:]).sum(1)
"multiply i and k dimensions and reduce j dimension"
i, j, k i, j, k
a: (2, 3) => (2, 3, None)
b: (3, 3) (None, 3, 3)
It should now be clear from this function decomposition that multiplication can be replaced with any binary operation, e.g. the equality operation.
Unfortunately, there is no generalized form of einsum (AFAIK) in pytorch that swaps the multiplication "out-of-the-box". There is however the einops library which is basically a wrapper around deep learning frameworks such as PyTorch.

Elements in a list are overwritten

I tried to program a function which creates the linear span of a list of independent vectors, but it seems that the last calculated vector overwrites all other elements. I'd be nice if someone could help me fixing it.
def span_generator(liste,n):
"""function to generate the span of a list of linear independent
vectors(in liste) in the n-dimensional vectorspace of a finite
field with characteristic 2, returns a list of all elements which
lie inside the span"""
results=[]
blank=[]
for i in range(n):
blank.append(0)
a=blank
if len(liste)>1:
listenwert=liste[-1]
liste.pop(-1)
values=span_generator(liste,n)
for i in range(2):
for j in range(len(values)):
for k in range(n):
a[k]=(i*listenwert[k]+values[j][k])%2
results.append(a)
else:
for i in range(2):
for j in range(n):
a[j]=(i*liste[0][j])
results.append(a)
print(results)
return results
print(span_generator([[1,0],[0,1]],2)) gives following results
[[1, 0], [1, 0]]
[[1, 1], [1, 1], [1, 1], [1, 1]]
[[1, 1], [1, 1], [1, 1], [1, 1]]
instead of the expected: [[0,0],[1,0],[0,1],[1,1]]
Edit: I tried to simplify the program with itertools.product, but it didn't solve the problem.
def span_generator(liste):
n=len(liste[0])
results=[]
coeff=list(itertools.product(range(2), repeat=n))
blank=[]
for i in range(n):
blank.append(0)
for i in range(len(coeff)):
a=blank
for j in range(len(coeff[0])):
for k in range(n):
a[k]=(a[k]+coeff[i][j]*liste[j][k])%2
results.append(a)
return results
Output: span_generator([[0,1],[1,0]])
[[0, 0], [0, 0], [0, 0], [0, 0]]
But it should give [[0,0],[0,1],[1,0],[1,1]]
Another example: span_generator([[0,1,1],[1,1,0]]) should give [[0,0,0],[0,1,1],[1,1,0],[1,0,1]] (2=0 since i'm calculating modulo 2)
Coefficients
You can use itertools.product to generate the coefficients:
n = len(liste[0])
coefficients = itertools.product(range(2), repeat=len(liste))
yields an iterator with this content:
[(0, 0), (0, 1), (1, 0), (1, 1)]
Linear combinations
You can then selectively multiply the results with the transpose of your liste (list(zip(*liste)))
for coeff in coefficients:
yield [sum((a * c) for a, c in zip(transpose[i], coeff)) for i in range(n)]
which take for each dimensionality (for i in range(n)) the sum of the products
def span_generator3(liste):
n = len(liste[0])
transpose = list(zip(*liste))
coefficients = itertools.product(range(2), repeat=len(liste))
for coeff in coefficients:
yield [sum((a * c) for a, c in zip(transpose[i], coeff)) % 2 for i in range(n)]
this produces an iterator. If you want the result in a list-form, just can list() on the iterator
Result
list(span_generator3([[1,2],[4,8]]))
output:
[[0, 0], [4, 8], [1, 2], [5, 10]]
Higher dimensions
list(sorted(span_generator3([[1,2, 4],[8, 16, 32], [64, 128, 256]])))
output:
[[0, 0, 0],
[1, 2, 4],
[8, 16, 32],
[9, 18, 36],
[64, 128, 256],
[65, 130, 260],
[72, 144, 288],
[73, 146, 292]]
Modulo 2
If you want the result modulo 2, that's just adding 2 characters in the right place
def span_generator3_mod2(liste):
n = len(liste[0])
transpose = list(zip(*liste))
coefficients = itertools.product(range(2), repeat=len(liste))
# print(list(itertools.product(range(2), repeat=len(liste))))
for coeff in coefficients:
yield [sum((a * c) for a, c in zip(transpose[i], coeff)) % 2 for i in range(n)]
list(span_generator3_mod2([[0,1,1],[1,1,0]])) gives
[[0, 0, 0], [1, 1, 0], [0, 1, 1], [1, 0, 1]]

Make specific elements of numpy matrix as 0

I have got index of 0 elements of Numpy Matrix (M) using:
index_array = numpy.argwhere(M == 0)
Now, I want to make these index elements (index present in index_array) as 0 in other matrix B. Is there any numpy way to do this?
For eg : index_array contains
[[2 1]
[4 4]]
, so make element present at (2,1) and (4,4) in Matrix B as 0.
You should have used np.where which returns a tuple of row and col index and thus can be used as indexing directly, instead of argwhere, so long as the index is not out of bound for B, you can do:
B[np.where(M == 0)] = 0
Example:
M = np.array([[1,2],[3,0],[0,1]])
M
#array([[1, 2],
# [3, 0],
# [0, 1]])
B = np.array([[1,2,3],[4,5,6],[7,8,9]])
B
#array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]])
B[np.where(M == 0)] = 0
B
#array([[1, 2, 3],
# [4, 0, 6],
# [0, 8, 9]])
If you want to stick to np.argwhere, you can get the row index and col index respectively and then do the assignment:
index_array = np.argwhere(M == 0)
B[index_array[:,0], index_array[:,1]] = 0

using for loop with in a for loop

For a given array v=[1,2,3] I am trying to print the sum of the product of each element with s for a range of s
import numpy as np
v=[1,2,3]
for s in range(0,5):
for i in range (0,3):
tot= np.multiply(v[i],s)
b.append(tot)
print (b)
my output is
[0, 0, 0, 1, 2, 3, 2, 4, 6, 3, 6, 9, 4, 8, 12]
I am trying to get the out put as
[[0, 0, 0], [1, 2, 3], [2, 4, 6], [3, 6, 9], [4, 8, 12]]
I am not quite sure how the second for loop is working inside the first for loop. If someone can explain that, it would be wonderful.
You'd create a new list for each iteration of the outer for loop:
v=[1,2,3]
b = []
for s in range(0,5):
result = []
for i in range (0,3):
tot= np.multiply(v[i],s)
result.append(tot)
b.append(result)
print (b)
You could just use * to multiply values, and you can iterate directly over v (no need to use a range)`:
v = [1, 2, 3]
b = []
for s in range(5):
result = []
for i in v:
result.append(i * s)
b.append(result)
You can replace both loops with list comprehensions:
b = [[i * s for i in v] for s in range(5)]
import numpy as np
v=np.array([1,2,3])
b=[]
for s in range(0,5):
b.append(list(v*s))
print (b)
Should do what you want. Don't forget numpy's extremely powerful broadcasting capability.
v=[1,2,3]
b=[]
for s in range(0,5):
b.append([])
for i in range (0,3):
tot= np.multiply(v[i],s)
b[s].append(tot)
print(b)

Resources