Want to change the range of for loop - python-3.x

I'm not sure how for loops work in Python 3:
l=6
for z in range(l):
print(z)
Can I change the value of l by setting l=10 from within the loop?
Will the value of l will be changed to 10 or will remain 6?
If not, how can I manipulate the range from within the loop?

No you cannot manipulate the range from within the loop.
range(l) will be evaluated once to a list containing numbers from 0 to l-1, when the code execution reaches the line with the for statement:
range(l) => [0, 1, 2, 3, 4, 5]
Then the for loop will assign the values in the list to z in order.
If you need more fine grained control you'd have to use a while loop and keep a counter manually:
l = 6
z = 0
while z < l:
print(z)
z = z + 1
l = 10
This would allow you to check on every iteration for a stopping criterion.

Related

Find H Index of the nodes of a graph using NetworkX

Definition of H Index used in this algorithm
Supposing a relational expression is represented as y = F(x1, x2, . . . , xn), where F returns an integer number greater than 0, and the function is to find a maximum value y satisfying the condition that there exist at least y elements whose values are not less than y. Hence, the H-index of any node i is defined as
H(i) = F(kj1 ,kj2 ,...,k jki)
where kj1, kj2, . . . , kjki represent the set of degrees of neighboring nodes of node i.
Now I want to find the H Index of the nodes of the following graphs using the algorithm given below :
Graph :
Code (Written in Python and NetworkX) :
def hindex(g, n):
nd = {}
h = 0
# print(len(list(g.neighbors(n))))
for v in g.neighbors(n):
#nd[v] = len(list(g.neighbors(v)))
nd[v] = g.degree(v)
snd = sorted(nd.values(), reverse=True)
for i in range(0,len(snd)):
h = i
if snd[i] < i:
break
#print("H index of " + str(n)+ " : " + str(h))
return h
Problem :
This algorithm is returning the wrong values of nodes 1, 5, 8 and 9
Actual Values :
Node 1 - 6 : H Index = 2
Node 7 - 9 : H Index = 1
But for Node 1 and 5 I am getting 1, and for Node 8 and 9 I am getting 0.
Any leads on where I am going wrong will be highly appreciated!
Try this:
def hindex(g, n):
sorted_neighbor_degrees = sorted((g.degree(v) for v in g.neighbors(n)), reverse=True)
h = 0
for i in range(1, len(sorted_neighbor_degrees)+1):
if sorted_neighbor_degrees[i-1] < i:
break
h = i
return h
There's no need for a nested loop; just make a decreasing list, and calculate the h-index like normal.
The reason for 'i - 1' is just that our arrays are 0-indexed, while h-index is based on rankings (i.e. the k largest values) which are 1-indexed.
From the definition of h-index: For a non-increasing function f, h(f) is max i >= 0 such that f(i) >= i. This is, equivalently, the min i >= 1 such that f(i) < i, minus 1. Here, f(i) is equal to sorted_neighbor_degrees[i - 1]. There are of course many other ways (with different time and space requirements) to calculate h.

Numpy cumsum with lower limit (vectorized)

I have an array and I would like to get the cumulative sum imposing a lower bound (lb=0) because in my array I have negative elements. Is it possible to vectorize it? I tried with a loop and numba.njit but the execution is slower than pure Python. Below an example of what I would like to get.
Example array:
a = numpy.array([1,1,-1,-1,-1,1,1])
What I get with numpy.cumsum:
[ 1 2 1 0 -1 0 1]
What I want:
[ 1 2 1 0 0 1 2]
The function with loop:
#numba.njit
def cumsum(array, lb=0):
result = numpy.zeros(array.size)
result[0] = array[0]
for k in range(1, array.size):
result[k] = max(lb, result[k-1]+array[k])
return result
When I execute the above, Numba is way faster than pure Python. Note that the first call to cumsum() (when decorated with #numba.njit) also does the compilation, so to be fair you should not time this first call. The second (and third and ...) call to cumsum() will be fast.

How to use built-in `slice` to access 2-d blocks in 2-d array?

I have a 2-d numpy array, for which I would like to modify 2-d blocks (like a 3x3 sub-block on a 9x9 sudoku board). Instead of using fancy indexing, I would like to use the built-in slice. Is there a way to make this work? I am thinking that the stride argument (third arg of slice) can be used to do this somehow, but I can't quite figure it out. My attempt is below.
import numpy as np
# make sample array (dim-1)
x = np.linspace(1, 81, 81).astype(int)
i = slice(0, 3)
print(x[i])
# [1 2 3]
# make sample array (dim-2)
X = x.reshape((9, 9))
Say I wanted to access the first 3 rows and first 3 columns of X. I can do it with fancy indexing as:
print(X[:3, :3])
# [[ 1 2 3]
# [10 11 12]
# [19 20 21]]
Trying to use similar logic to the dim-1 case with slice:
j = np.array([slice(0,3), slice(0,3)]) # wrong way to acccess
print(X[j])
Throws the following error:
IndexError: arrays used as indices must be of integer (or boolean) type
If you subscript with X[:3, :3], then behind the curtains you pass a tuple, so (slice(3), slice(3)).
So you can construct a j with:
j = (slice(3), slice(3))
or you can obtain the a, b block with:
j = (slice(3*a, 3*a+3), slice(3*b, 3*b+3))
so here a=0 and b=1 for example will yield the X[0:3, 3:6] part. So a block that contains the first three rows and second three columns.
or you can make a tuple with a variable number of items. For example for an n-dimensional array, you can make an n-tuple that each has a slice(3) object:
j = (slice(3),) * n

How to generate 1825 numbers with a step of 0.01 in a specific range

In the following code I want to get len(a) should be 1825 keeping step 0.01. But when I print len(a) it gives me 73. For getting length of 1825 I have to generate numbers from 2.275 to 3 with a step of 0.01 ,73 times. How can I do that? I tried to use np.linspace but that command doesn't work for this case.
a = np.arange(2.275, 3, 0.01)
Seems like you want to np.random.choice 1825 times
>>> a = np.arange(2.275,3,0.01)
>>> c = np.random.choice(a, 1825)
array([2.995, 2.545, 2.755, ..., 2.875, 2.275, 2.605])
>>> c.shape
(1825,)
Edit
If you want a repeated 25 times (i.e. 1825/73) in sequence, use np.tile()
target = 1825
n = target/len(a)
np.tile(a, int(n))
yields
array([2.275, 2.285, 2.295, ..., 2.975, 2.985, 2.995])
Here's a one liner, given a = np.arange(2.275, 3, 0.01) and n = 1825:
a = np.broadcast_to(a, (n // a.size + book(n % a.size), a.size)).ravel()[:n]
This uses np.broadcast_to to turn a into a matrix where it repeats itself enough times to fill 1825 elements. ravel then flattens the repeated list and the final slice chops off the unwanted elements. The ravel operation is what actually copies the list since the broadcast uses stride tricks to avoid copying the data.

Stuck on a Concurrent programming example, in pseudocode(atomic actions/fine-grained atomicity)

My book presents a simple example which I'm a bit confused about:
It says, "consider the following program, and assume that the fine-grained atomic actions are reading and writing the variables:"
int y = 0, z = 0;
co x = y+z; // y=1; z=2; oc;
"If x = y + z is implemented by loading a register with y and then adding z to it, the final value of x can be 0,1,2, or 3. "
2? How does 2 work?
Note: co starts a concurrent process and // denote parallel-running statements
In your program there are two parallel sequences:
Sequence 1: x = y+z;
Sequence 2: y=1; z=2;
The operations of sequence 1 are:
y Copy the value of y into a register.
+ z Add the value of z to the value in the register.
x = Copy the value of the register into x.
The operations of sequence 2 are:
y=1; Set the value of y to 1.
z=2; Set the value of z to 2.
These two sequences are running at the same time, though the steps within a sequence must occur in order. Therefore, you can get an x value of '2' in the following sequence:
y=0
z=0
y Copy the value of y into a register. (register value is now '0')
y=1; Set the value of y to 1. (has no effect on the result, we've already copied y to the register)
z=2; Set the value of z to 2.
+ z Add the value of z to the value in the register. (register value is now '2')
x = Copy the value of the register into x. (the value of x is now '2')
Since they are assumed to run in parallel, I think an even simpler case could be y=0, z=2 when the assignment x = y + z occurs.

Resources