Efficient way to calculate 3D matrix multiplication using numpy - 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.

Related

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

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()

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

Outer difference along axis in tensorflow

Given a tensor T_0 of shape (I,J,K), I am trying to think of an efficient way to construct a new tensor T_1 of shape (I,I,J,K), whose elements are T_1[i1, i2, j, k] = T_0[i1, j, k] - T_0[i2, j, k]
Here is a pedestrian approach with 2 loops:
outer_list = [None] * I
for i1 in range(I):
inner_list = [0] * I
for i2 in range(I):
inner_list[i2] = T_0[i1] - T_0[i2]
outer_list [cl] = tf.stack(tf.stack(inner_list))
T_1 = tf.stack(outer_list )
Here is a pedestrian approach with 1 loop:
outer_list = [None] * I
for i1 in range(I):
outer_list[i1] = T_0[i1 : i1+1] - T_0
T_1 = tf.stack(outer_list )

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

How to express c[i,j,k] = a[i,j] * b[i,k] in Numpy/Theano?

The definition
c[i,j,k] = a[i,j] * b[i,k] for any i, j, k
is an element-wise product with respect to i, and an outer product with respect to j and k. Is there any way to express this in NumPy/Theano without loops?
I found a solution that works with both Numpy and Theano:
c = a[:, :, np.newaxis] * b[:, np.newaxis, :]