Tensorflow efficient overlap-add - python

I'm trying to implement overlap-add in Tensorflow but I'm struggling to convert the numpy output_seq[start:end] += chunk to Tensorflow. Right now I'm output_seq = output_seq + tf.pad(chunk, [[start, length - end]]) but that's really slow on long sequences.
I also have a hunch there might be tricks you can do with gather/scatter, but I can't quite figure it out. Below is my brute force attempt:
import tensorflow as tf
input = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
def overlap_add(overlap):
with tf.Graph().as_default(), tf.Session() as sess:
x = tf.constant(input)
num_chunks = tf.shape(x)[0]
chunk_size = tf.shape(x)[1]
hop_length = chunk_size - overlap
out_len = chunk_size + hop_length * (num_chunks - 1)
y = tf.zeros((out_len,), dtype=tf.int32)
def body(i, y):
j = i * hop_length
padding = [[j, out_len - (j + chunk_size)]]
chunk = x[i]
y = y + tf.pad(chunk, padding)
return (i + 1, y)
i = tf.constant(0)
i, y = tf.while_loop(
cond=lambda i, _: tf.less(i, num_chunks),
body=body,
loop_vars=[i, y])
return sess.run(y)
for i in range(4):
print 'overlap_add(%d): %s' % (i, overlap_add(i))
# overlap_add(0): [ 1 2 3 4 5 6 7 8 9 10 11 12]
# overlap_add(1): [ 1 2 3 9 6 7 17 10 11 12]
# overlap_add(2): [ 1 2 8 10 16 18 11 12]
# overlap_add(3): [ 1 7 18 21 19 12]

UPDATE: There's now an overlap_and_add function in Tensorflow itself.
OLD ANSWER:
Trawled through the docs and found unsorted_segment_sum:
import tensorflow as tf
input = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
def tf_repeat(a, repeats):
return tf.reshape(tf.tile(tf.reshape(a, [-1, 1]),
[1, repeats]), [-1])
def overlap_add(overlap):
with tf.Graph().as_default(), tf.Session() as sess:
x = tf.constant(input)
x_flat = tf.reshape(x, [-1])
num_chunks = tf.shape(x)[0]
chunk_size = tf.shape(x)[1]
hop_len = chunk_size - overlap
flat_len = num_chunks * chunk_size
out_len = chunk_size + hop_len * (num_chunks - 1)
# e.g. [0,1,2,3, 2,3,4,5, 4,5,6,7] for overlap == 2
indexes = tf.range(flat_len) - tf_repeat(tf.range(num_chunks), chunk_size) * overlap
return sess.run(tf.unsorted_segment_sum(x_flat, indexes, out_len))
for i in range(4):
print 'overlap_add(%d): %s' % (i, overlap_add(i))
# overlap_add(0): [ 1 2 3 4 5 6 7 8 9 10 11 12]
# overlap_add(1): [ 1 2 3 9 6 7 17 10 11 12]
# overlap_add(2): [ 1 2 8 10 16 18 11 12]
# overlap_add(3): [ 1 7 18 21 19 12]

You can use slices in Tensorflow as well:
a[1:3].assign(a[1:3] + b[1:3]).eval()
For some reason assign_add is not implemented. It seems like a bug to me.
a[1:3].assign_add(b[1:3]).eval() # Doesn't work

Related

Repeating digits in the Pythagorean triad

I have written a fun that counts pitagorian triad:
def triad(N):
for a in range(1,N):
for b in range(1,N):
for c in range(1,N):
if a*a+b*b==c*c and a!=b and b!=a:
print(a,b,c)
print('-'*10)
triad(20)
but the output is:
3 4 5
----------
4 3 5
----------
5 12 13
----------
6 8 10
----------
8 6 10
----------
8 15 17
----------
9 12 15
----------
12 5 13
----------
12 9 15
----------
15 8 17
----------
and I don't want:
3 4 5
----------
4 3 5
---------
and
6 8 10
----------
8 6 10
----------
How to get rid of repeating digits?
I tried a!=b and b!=a
One approach is to start b as a + 1 and c as a + 2:
def triad(N):
for a in range(1, N):
for b in range(a + 1, N):
for c in range(a + 2, N):
if a * a + b * b == c * c:
print(a, b, c)
print('-' * 10)
triad(20)
Output
3 4 5
----------
5 12 13
----------
6 8 10
----------
8 15 17
----------
9 12 15
----------
You could use the "tree of primitive Pythagorian triples":
def pythagorianTriples(n):
def mul(m, a): # Multiplication of matrix with vector
return [sum(x * y for x, y in zip(row, a)) for row in m]
matrices = (
(
(1, -2, 2),
(2, -1, 2),
(2, -2, 3)
), (
(1, 2, 2),
(2, 1, 2),
(2, 2, 3)
), (
(-1, 2, 2),
(-2, 1, 2),
(-2, 2, 3)
)
)
q = [[3, 4, 5]]
while q:
a = q.pop()
b = sorted(a)
if b[-1] <= n:
# yield this triple and multiples of it
while b[-1] <= n:
yield b
for i in range(3):
b[i] += a[i]
# add 3 more triples to the list
q.extend(mul(m, a) for m in matrices)
for res in pythagorianTriples(20):
print(res)
This outputs:
[3, 4, 5]
[6, 8, 10]
[9, 12, 15]
[12, 16, 20]
[8, 15, 17]
[5, 12, 13]
Another solution without the 3rd loop and much efficient
import math
def triad(N):
for a in range(1, N):
for b in range(a + 1, N):
sq = a * a + b * b
c = int(math.sqrt(sq))
if sq == c * c and c > b:
print(a, b, c)
print('-' * 10)
triad(20)
Another approach would be:
def triad(N):
for a in range(1,N):
for b in range(1,N):
for c in range(1,N):
if (a*a + b*b) == c*c and a < b:
print(a,b,c)
print(10*"-")
triad(20)
Output:
3 4 5
----------
5 12 13
----------
6 8 10
----------
8 15 17
----------
9 12 15
----------
Another approach using itertools
One thing about combinations is it returns the items in the same order as the iterable so it's safe to assume that the 3rd item is the only possible hypotenuse.
from itertools import combinations
from math import sqrt
def triad(N):
return [c for c in combinations(range(1, N), 3)
if sqrt(c[0]**2 + c[1]**2) == c[2]]
print(triad(20))
Output:
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15)]

How can i build matrices in numpy

I want to build a matrix in NumPy in which the items add up to each other. So I have tried to build it with the following code:
StartpointRow = int(input("First number of row?:\n"))
EndpointRow = int(input("Last number of row?:\n"))
StepRow = int(input("Which steps should the row have?:\n"))
StartpointCol = int(input("First number of column?:\n"))
EndpointCol = int(input("Last number of column?:\n"))
StepCol = int(input("Which steps should the column have?:\n"))
x = np.array([[i+j for i in range(StartpointCol, EndpointCol , StepCol)]
for j in range(StartpointRow, EndpointRow , StepRow)])
print(x)
let's say that, for instance, I enter 1,4,1 and 1,4,1. I want the solution to be a matrix like this:
1 2 3 4
2 4 5 6
3 5 6 7
4 6 7 8
Not like that:
2 3 4
3 4 5
4 5 6
or If the user types in: 1,4,1 and 2,4,1.
0 1 2 3 4
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
not like that:
3 4
4 5
5 6
Could you help me out?
Use np.add.outer:
def build(r_start, r_stop, r_step, c_start, c_stop, c_step):
r = np.arange(r_start, r_stop + 1, r_step)
c = np.arange(c_start, c_stop + 1, c_step)
if r_start == c_start:
ret = np.empty((c.size, r.size), int)
ret[:, 0] = c
ret[0, :] = r
else:
ret = np.empty((c.size + 1, r.size + 1), int)
ret[0, 0] = 0
ret[1:, 0] = c
ret[0, 1:] = r
np.add.outer(ret[1:, 0], ret[0, 1:], out=ret[1:, 1:])
return ret
A little simplification:
def build(r_start, r_stop, r_step, c_start, c_stop, c_step):
r = np.arange(r_start, r_stop + 1, r_step)
c = np.arange(c_start, c_stop + 1, c_step)
ne = int(r_start != c_start)
ret = np.empty((c.size + ne, r.size + ne), int)
ret[0, 0] = 0
ret[ne:, 0] = c
ret[0, ne:] = r
np.add.outer(ret[1:, 0], ret[0, 1:], out=ret[1:, 1:])
return ret
Test:
>>> build(1, 4, 1, 1, 4, 1)
array([[1, 2, 3, 4],
[2, 4, 5, 6],
[3, 5, 6, 7],
[4, 6, 7, 8]])
>>> build(1, 4, 1, 2, 4, 1)
array([[0, 1, 2, 3, 4],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
I think your test cases are wrong.
What I understand you mean is that each row and each column have a starting number, what needs to be done is to add the two and generate the matrix according to step.
If the user types in: 1,4,1 and 1,4,1, what he can get is:
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
And if the user types in: 1,4,1 and 2,4,1, what he can get is:
3 4 5
4 5 6
5 6 7
6 7 8
And my code is:
import numpy as np
StartpointRow = int(input("First number of row?:\n"))
EndpointRow = int(input("Last number of row?:\n"))
StepRow = int(input("Which steps should the row have?:\n"))
StartpointCol = int(input("First number of column?:\n"))
EndpointCol = int(input("Last number of column?:\n"))
StepCol = int(input("Which steps should the column have?:\n"))
x = np.array([[i+j for i in range(StartpointCol, EndpointCol + 1 , StepCol)]
for j in range(StartpointRow, EndpointRow + 1, StepRow)])
print(x)

How to make with lists?

How to make a multiplication chart with nested lists and for ? I need to all numbers from first list multiply to from second list
chart = [
[],
[],
]
for i in range(1,len(chart)+1):
for j in range(i,i*len(chart)+1):
print(f'{i} * {j} = {i*j}')
In python positions of elements in a list start from 0.
The chart list contains 2 lists:
chart[0] = [1, 2, 3, 4, 5]
chart[1] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
What you want to do is access the elements of the first list and multiply by elements of the second list.
for i in range(len(chart[0])): # range(5) => 0, 1, 2, 3, 4
for j in range(len(chart[1])): # range(10) => 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
print(f'{chart[0][i]} * {chart[1][j]} = {chart[0][i] * chart[1][j]}
itertools.product will produce the desired output, creating 2-tuples consisting of one element from the first list and one element from the second list:
import itertools
chart = [
[1,2,3,4,5],
[1,2,3,4,5,6,7,8,9,10],
]
for i, j in itertools.product(*chart):
print(f'{i} * {j} = {i*j}')
Use a cartesian product:
chart = [[1,2,3,4,5],[1,2,3,4,5,6,7,8,9,10]]
>>> print('\n'.join([f'{i} * {j} = {i*j}' for i in chart[0] for j in chart[1]]))
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
1 * 4 = 4
...
4 * 10 = 40
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
5 * 7 = 35
5 * 8 = 40
5 * 9 = 45
5 * 10 = 50

Vectorized method to compute Hankel matrix for multi-input, multi-output data sequence

I'm constructing a Hankel matrix and wondered if there's a way to further vectorize the following computation (i.e. without for loops or list comprehensions).
# Imagine this is some time-series data
q = 2 # Number of inputs
p = 2 # Number of outputs
nt = 6 # Number of timesteps
y = np.array(range(p*q*nt)).reshape([nt, p, q]).transpose()
assert y.shape == (q, p, nt)
print(y.shape)
(2, 2, 6)
print(y[:,:,0])
[[0 2]
[1 3]]
print(y[:,:,1])
[[4 6]
[5 7]]
print(y[:,:,2])
[[ 8 10]
[ 9 11]]
Desired results
# Desired Hankel matrix
m = n = 3 # dimensions
assert nt >= m + n
h = np.zeros((q*m, p*n), dtype=int)
for i in range(m):
for j in range(n):
h[q*i:q*(i+1), p*j:p*(j+1)] = y[:, :, i+j]
print(h)
[[ 0 2 4 6 8 10]
[ 1 3 5 7 9 11]
[ 4 6 8 10 12 14]
[ 5 7 9 11 13 15]
[ 8 10 12 14 16 18]
[ 9 11 13 15 17 19]]
(Note how the 2x2 blocks are stacked)
# Alternative method using stacking
b = np.hstack([y[:,:,i] for i in range(y.shape[2])])
assert b.shape == (q, p*nt)
print(b)
[[ 0 2 4 6 8 10 12 14 16 18 20 22]
[ 1 3 5 7 9 11 13 15 17 19 21 23]]
h = np.vstack([b[:, i*p:i*p+n*q] for i in range(m)])
print(h)
[[ 0 2 4 6 8 10]
[ 1 3 5 7 9 11]
[ 4 6 8 10 12 14]
[ 5 7 9 11 13 15]
[ 8 10 12 14 16 18]
[ 9 11 13 15 17 19]]
You can use stride_tricks:
>>> from numpy.lib.stride_tricks import as_strided
>>>
>>> a = np.arange(20).reshape(5,2,2)
>>> s0,s1,s2 = a.strides
>>> as_strided(a,(3,2,3,2),(s0,s2,s0,s1)).reshape(6,6)
array([[ 0, 2, 4, 6, 8, 10],
[ 1, 3, 5, 7, 9, 11],
[ 4, 6, 8, 10, 12, 14],
[ 5, 7, 9, 11, 13, 15],
[ 8, 10, 12, 14, 16, 18],
[ 9, 11, 13, 15, 17, 19]])

Decimal expansion based on slot length summation

I'm trying to create an algorithm to produce a decimal number by certain way.
a) I have an initial number say i = 2.
b) Then I have an incremental addition method, say f(n) { n * 2 }.
c) Then I have a slot length for digits say l = 2, that creates front zeros for small numbers and limits max length of the longer numbers. 2 becomes 02, 64 is 64, but 512 = (5)12 where 5 is moved backward on previous slot
d) Max slots is the fourth parameter, m = 10
e) Finally I want to compute value by summing up digit from slots and using it as a decimal part of the 0.
So with given example:
i=2
f(n)=n*2
l=2
m=10
outcome should be produced in this manner:
step 1)
02 04 08 16 32 64 128 256 512 1024
step 2)
02 04 08 16 32 64
1 28
2 56
5 12
10 24
->
slot: 1 2 3 4 5 6 7 8 9 10
computed: 02 04 08 16 32 65 30 61 22 24
step 3)
I have a number: 02040816326530612224 or 0.02040816326530612224 as stated on part e).
Note that if max slot is bigger in this example, then numbers on slots 9 and 10 will change. I also want to have part b) as a function, so I can change it to other like fib(nx) {n1+n2}.
I prefer Python as a computer language for algo, but anything that is easy to transform to Python is acceptable.
ADDED
This is a function I have managed to create so far:
# l = slot length, doesnt work with number > 2...
def comp(l = 2):
a = []
# how to pass a function, that produces this list?
b = [[0, 2], [0, 4], [0, 8], [1, 6], [3, 2], [6, 4], [1, 2, 8], [2, 5, 6], [5, 1, 2], [1, 0, 2, 4], [2, 0, 4, 8]]
r = 0
# main algo
for bb in b:
ll = len(bb)
for i in range(0, ll):
x = r + i - ll + l
# is there a better way to do following try except part?
try:
a[x] += bb[i]
except IndexError:
a.append(bb[i])
# moving bits backward, any better way to do this?
s = a[x] - 9
d = 0
while s > 0:
d += 1
a[x] -= 10
a[x-d] += 1
s = a[x-d] - 9
r += l
return '0.' + ''.join(map(str, a))
def doub(n):
return pow(2, n)
def fibo(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
def fixed_slot_numbers(f, l, m):
b = []
for n in range(1, m):
a = [int(c) for c in str(f(n))]
while len(a) < l:
a.insert(0, 0)
b.append(a)
return b
def algo(function, fixed_slot_length = 2, max_slots = 12):
a = []
slot_numbers = fixed_slot_numbers(function, fixed_slot_length, max_slots)
for r, b in enumerate(slot_numbers):
r *= fixed_slot_length
slot_length = len(b)
for bidx in range(0, slot_length):
aidx = r + bidx - slot_length + fixed_slot_length
try:
a[aidx] += b[bidx]
except IndexError:
a.append(b[bidx])
d = 0
while a[aidx-d] > 9:
a[aidx-d] -= 10
d += 1
a[aidx-d] += 1
return '0.%s' % ''.join(map(str, a))
algo(doub, 2, 28) -> 0.020408163265306122448979591836734693877551020405424128 = 1/49
algo(fibo, 1, 28) -> 0.112359550561797752808950848 = 10/89

Categories

Resources