How to create a graph of 2n nodes on a circle w/ each node is connected to all others except the opposite node + f(n) on either side of the opposite - numpy

I would like to create a graph that puts 2n points spaced uniformly on a unit circle, and connects each node to all other nodes except the opposite node, as well as k nodes on either side of the opposite node, where k is a function of n.
I am using the NetworkX package to create the graph.
I know how to manually specify the number of nodes to exclude on either side of the opposite node, but I don't know how to use a function of n instead of doing it manually. I'm sure it is quite simple, but how can this be done?
For example, the code below will exclude the opposite node as well as 5 nodes on either side of the opposite node.
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
def create_circle_graph(n):
G = nx.Graph()
theta = np.linspace(0, 2*np.pi, 2*n, endpoint=False)
for i in range(2*n):
G.add_node(i, pos=np.array([np.cos(theta[i]), np.sin(theta[i])]))
for j in range(i+1, 2*n):
if (i + n) % (2 * n) != j and (i + n + 1) % (2 * n) != j and (i + n - 1) % (2 * n) != j and (i + n + 2) % (2 * n) != j and (i + n - 2) % (2 * n) != j and (i + n + 3) % (2 * n) != j and (i + n - 3) % (2 * n) != j and (i + n + 4) % (2 * n) != j and (i + n - 4) % (2 * n) != j and (i + n + 5) % (2 * n) != j and (i + n - 5) % (2 * n) != j:
G.add_edge(i, j)
return G
n = 10
G = create_circle_graph(n)
pos = nx.get_node_attributes(G, 'pos')
nx.draw(G, pos, with_labels=True)
plt.show()

The main difficulty is to find the appropriate if statement while creating the edges. Once you figure that part out the rest is pretty straightforward since you can use nx.circular_layout(G) to automatically position your nodes.
Below is a possible approach for this task:
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
def create_circle_graph(n,k): #2*n the number and k the radius of the neighborhood
G = nx.Graph()
[G.add_node(i) for i in range(2*n)] # create nodes
for i in range(2*n):
for j in range(2*n):
if i<j and (j-i<n-k or j-i>n+k): #appropriate if statement for this task
G.add_edge(i,j)
return G
And here is an example of the code with n=5 and varying values for k:
n=5
fig,axs=plt.subplots(1,5,figsize=(15,10))
for k,ax in enumerate(fig.axes): #loop through k and subplots
G=create_circle_graph(n,k)
posG=nx.circular_layout(G) #set up positions for the nodes
ax.set_title('k='+str(k))
nx.draw(G,pos=posG,with_labels=True,ax=ax)
ax.set_aspect('equal')
plt.tight_layout()
plt.show()

Related

Sympy simplify sum of Kronecker delta

How does one simplify sums of Kronecker delta expressions in sympy?
For example consider Sum(KroneckerDelta(i,j),(i,0,n-1)) or Sum(KroneckerDelta(i, j, (0, n - 1)), (i, 0, n - 1)):
from sympy import *
from sympy.concrete.delta import _simplify_delta
n = symbols('n')
j = tensor.Idx('j')
i = tensor.Idx('i')
_simplify_delta(simplify(Sum(KroneckerDelta(i,j),(i,0,n-1))))
_simplify_delta(simplify(Sum(KroneckerDelta(i,j,(0,n-1)),(i,0,n-1))))
Outputs Sum(KroneckerDelta(i, j), (i, 0, n - 1)) and Sum(KroneckerDelta(i, j, (0, n - 1)), (i, 0, n - 1))
If j is constrained to be between 0 and n-1 (how do I tell the sympy that?), then this should reduce to 1, which occurs at i==j. Moreover if the sum is more complicated, I would expect it to remove the sum and replace the sum variable i with the variable j.
Moreover, I would be interested in a resource for all sorts of simplifications in sympy for KroneckerDelta functions. I recently found out how to perform implicit matrix differentiation in sympy and KroneckerDelta functions appear everywhere.
Edit: I found a solution, kind of. Its not automated.
I found more functions inside of sympy.concrete.delta using help(sympy.concrete.delta). If we copy the resulting expression and replace Sum with sympy.concrete.delta.deltasummation then the desired simplification happens. I am still curious if there is a delta simplification package that tries all these things automatically.
You can evaluate summations using Sum().doit() or summation:
In [1]: from sympy import *
...: from sympy.concrete.delta import _simplify_delta
...:
...: n = symbols("n")
...: j = tensor.Idx("j")
...: i = tensor.Idx("i")
In [2]: s = Sum(KroneckerDelta(i, j), (i, 0, n - 1))
In [3]: s
Out[3]:
n - 1
___
╲
╲ δ
╱ i,j
╱
‾‾‾
i = 0
In [4]: s.doit()
Out[4]:
⎧1 for j ≥ 0 ∧ j ≤ n - 1
⎨
⎩0 otherwise
In [5]: summation(KroneckerDelta(i, j), (i, 0, n - 1))
Out[5]:
⎧1 for j ≥ 0 ∧ j ≤ n - 1
⎨
⎩0 otherwise
There isn't currently a way to specify in assumptions that j<=n-1 although you can use j = symbols('j', nonnegative=True) to specify that j>=0. You can also manually replace those conditions with true though e.g.:
In [8]: s.doit().subs({j >= 0: True, j <= n-1: True})
Out[8]: 1
The second summation where you give bounds for the KroneckerDelta will compute automatically:
In [11]: s2 = Sum(KroneckerDelta(i, j, (0, n - 1)), (i, 0, n - 1))
In [12]: s2
Out[12]:
n - 1
___
╲
╲ δ
╱ i,j
╱
‾‾‾
i = 0
In [13]: s2.doit()
Out[13]: 1

Efficient way to calculate 3D matrix multiplication using numpy

How can I efficiently write and calculate this multiplication using numpy:
for k in range(K):
for i in range(SIZE):
for j in range(SIZE):
for i_b in range(B_SIZE):
for j_b in range(B_SIZE):
for k_b in range(k+1):
data[k, i * w + i_b, j * h + j_b] += arr1[k_b, i_b, j_b] * arr2[k_b, i, j]
For example:
SIZE, B_SIZE = 32, 8
arr1.shape -> (8, 8, 8)
arr2.shape -> (8, 32, 32)
data.shape -> (K, 256, 256)
Thank you.
You can use Numba for such kind of non-trivial case and rework the loops to use efficiently the CPU cache. Here is an example:
import numba as nb
#nb.njit
def compute(data, arr1, arr2):
for k in range(K):
for k_b in range(k+1):
for i in range(SIZE):
for j in range(SIZE):
tmp = arr2[k_b, i, j]
for i_b in range(B_SIZE):
for j_b in range(B_SIZE):
data[k, i * w + i_b, j * h + j_b] += arr1[k_b, i_b, j_b] * tmp
If you do this operation once, then you can pre-compile the Numba code by providing the types of the arrays. If K is big, then you can parallelize the code using #nb.njit(parallel=True) and use for k in nb.prange(K) rather than for k in range(K). This should be several order of magnitude fater.

Division by Zero error in calculating series

I am trying to compute a series, and I am running into an issue that I don't know why is occurring.
"RuntimeWarning: divide by zero encountered in double_scalars"
When I checked the code, it didn't seem to have any singularities, so I am confused. Here is the code currently(log stands for natural logarithm)(edit: extending code if that helps):
from numpy import pi, log
#Create functions to calculate the sums
def phi(z: int):
k = 0
phi = 0
#Loop through 1000 times to try to approximate the series value as if it went to infinity
while k <= 100:
phi += ((1/(k+1)) - (1/(k+(2*z))))
k += 1
return phi
def psi(z: int):
psi = 0
k = 1
while k <= 101:
psi += ((log(k))/( k**(2*z)))
k += 1
return psi
def sig(z: int):
sig = 0
k = 1
while k <= 101:
sig += ((log(k))**2)/(k^(2*z))
k += 1
return sig
def beta(z: int):
beta = 0
k = 1
while k <= 101:
beta += (1/(((2*z)+k)^2))
k += 1
return beta
#Create the formula to approximate the value. For higher accuracy, either calculate more derivatives of Bernoulli numbers or increase the boundry of k.
def Bern(z :int):
#Define Euler–Mascheroni constant
c = 0.577215664901532860606512
#Begin computations (only approximation)
B = (pi/6) * (phi(1) - c - 2 * log(2 * pi) - 1) - z * ((pi/6) * ((phi(1)- c - (2 * log(2 * pi)) - 1) * (phi(1) - c) + beta(1) - 2 * psi(1)) - 2 * (psi(1) * (phi(1) - c) + sig(1) + 2 * psi(1) * log(2 * pi)))
#output
return B
A = int(input("Choose any value: "))
print("The answer is", Bern(A + 1))
Any help would be much appreciated.
are you sure you need a ^ bitwise exclusive or operator instead of **? I've tried to run your code with input parameter z = 1. And on a second iteration the result of k^(2*z) was equal to 0, so where is from zero division error come from (2^2*1 = 0).

How to generate Im, Re octave filter

I have function, which convert result from FFT to octave band (or 1/n - octave):
Function OctaveFilter(LowFreq, HighFreq, Im, Re) 'For amplitude
Dim i, j, SortedData(), F_From(), F_To()
Redim SortedData(Bins * n), F_From(Bins * n), F_To(Bins * n)
Dim p
For i = 1 To Bins * n
F_To(i) = Int(HighFreq(i) / df)
F_From(i) = Int(LowFreq(i) / df)
if (F_From(i) = 0) Then F_From(i) = 1 ' We cannot start from index 0
Next
For i = 1 To Bins * n
SortedData(i) = 0
For j = F_From(i) To F_To(i)
If (Length >= j) Then
SortedData(i) = SortedData(i) + Im(j)^2 + Re(j)^2
End If
Next
Next
SortInBins = sqrt(SortedData)
End Function
For example this FFT:
Amplitude
converts to this 1/3- octave bands:
1/3 - octave
But from FFT I also have Re and Im part. I want to convert these parts to octave band too. Is it the same function? How can I convert this Im part imaginary part to similar result (1/3 - octave) ?

How to vectorise an integration function?

I'm a beginner in numpy and I want to vectorise this function:
I don't quite understand what I need to do but this is what I've come up with:
n = 1000000
h = 1/n
x = np.arange(1,n,1)
def f(x):
return x ** 3
def rec(x):
result = np.zeros_like(x)
result[x < n] = f((x[x < n])*h)
return result
integral = 0.5*h + h*rec(x)
print integral
I end up with an array of 0's. Could someone please point me in the right direction?
Try:
def trap(f, a, b, n):
xs = np.linspace(a, b, n + 1)
ys = f(xs)
return (0.5 * ys[0] + 0.5 * ys[-1] + np.sum(ys[1:-1])) * (b - a) / n