how to do this interpolation formula faster? - python

I have a function of Everett interpolation and I'd like to make it a little bit faster than it is right now. It works very well b
x and y are the parameters: time and values.
xi is the time which I want to have interpolated value.
def everett(x,y,xi):
'''
function everett
INPUT:
x list float
y list float
xi float
RETURN:
yi float
'''
n = len(x) #interpolation degree
h = x[1]-x[0] #differences between epochs
D = np.zeros([n,n+1])
D[:,0] = x
D[:,1] = y
for j in range(1,n): #loop to each column
for i in range(0,n-j): #loop to cell within a column
D[i,j+1] = D[i+1,j] - D[i,j]
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
z = i
w = 1 - u
i = 0
yi = 0
m1 = u
m2 = w
for j in range(1,n+1,2):
yi += m1 * D[z+1-i,j] + m2 * D[z-i,j]
i = i + 1
m1 *= (u - i) * (u + i) / ((j+1)*(j+2))
m2 *= (w - i) * (w + i) / ((j+1)*(j+2))
if (z-i)<0 or (z+1-i)>(n-j-1):
break #//checks validity of index in the table
return yi
Thx!
EDIT: some modification using numpy
I change this part of code:
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
by this one:
#Finding the value of u
u = (xi - x) /h
u0 = np.where(u == 0)[0]
if u0.size:
return y[u0[0]]
i = np.where((u > 0) & (u < 1.0))[0]
if not i.size:
return None
z = i[0]
u = u[z]
the biggest problem I have right now is how to modify the last loop and the first loop where variable D is filled with values.
Any ideas?

Include numpy, put the data into numpy.array()s and use numpy operations. You'll simplify your code and get, potentially, orders of magnitude better performance. If you're comfortable with Matlab, you'll find numpy easy to learn.
Loops like
for i in range(0,n):
u = ( xi - x[i] ) / h
become simple one liners:
u = (xi - x) / h
(where x is an array, u will be an array and the - and / will do element-wise arithmetic if xi and h are numbers)
This even works for whole arrays. For example, a forward difference can be expressed in 1D as
Dx = X[1:] - x[:1]
The X[1:] means the elements of X excluding the first and X[:1] means the elements of X excluding the last.
You can do the same on N-dimensional arrays, eliminating nested loops.
I wrote this article a long time ago, but it's still relevant. You'll see where I use numpy to speed up a finite difference calculation on a mesh (solving the 2D diffusion equation) while also simplifying the code: http://www.timteatro.net/2010/10/29/performance-python-solving-the-2d-diffusion-equation-with-numpy/
If I get a chance, I will come back and help you work on your specific code. But actually, I think this algorithm is a perfect project to introduce yourself to numpy.
And, if you're more interested in the result than you are the method, SciPy (an extension of numpy) has interpolation functions:
http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html

Related

Using a 2D random walk numerical solution to solve an equation. Have the methodology but not the execution. Details in post

Essentially, I am trying to solve the lapalcian using a random walk numerical solution. My domain is a circle, and the boundary condition is some function: f(phi) = cos(2phi). Essentially, I am trying to take a point within the 2D domain of my (unit) circle, randomly walk it until it meets the edge of the circle, so when x^2 + y+2 = 1. I am then going to take the x and y coordinate, find theta, then plug theta into my function to obtain a value. I will record and store this value, and repeat this process 'NumbRepeats' times. Then take the average of these values. This should give an approximate solution to the equation. I am not so concerned about the physics per se, I need help in what I have listed above the process I have described above. It may not necesarily be correct, but if I can get the program to do what I think is correct, then I will be happy. Thanks for the help. I will post my code below:
Note, my expertise is not coding, so apologies if this is difficult to understand. Any help is appreciated.
import matplotlib.pyplot as plt
import numpy as np
import random
#Python code for 2D random walk
# defining the number of steps
n = 100000
#creating two array for containing x and y coordinate
#of size equals to the number of size and filled up with 0's
x = np.zeros(n)
y = np.zeros(n)
NumbRepeats = 100
PotBoundVec = []
for j in range(NumbRepeats):
PotBound = 0
for i in range(1, n):
val = random.randint(0, 1)
if val == .25:
x[i] = x[i - 1] + 1
y[i] = y[i - 1]
elif val == .5:
x[i] = x[i - 1] - 1
y[i] = y[i - 1]
elif val == .75:
x[i] = x[i - 1]
y[i] = y[i - 1] + 1
else:
x[i] = x[i - 1]
y[i] = y[i - 1] - 1
if x[i]**2 + y[i]**2 == 1:
Theta = np.tan(x[i]/y[i])
PotBound = np.cos(2*Theta)
PotBoundVec.append(PotBound)
x = np.zeros(n)
y = np.zeros(n)
else:
pass
print(PotBoundVec)

Individual operations on coordinates in 2D arrays

Im working on a problem with projectile motion in computational physics, and I want to perform different mathematical operations on the x and y coordinates in my array. The code Im struggling with is indexing inside a for loop.
I've tried different forms for indexing but keep getting errors like "could not broadcast input array from shape (2,2) into shape (2)" and "setting an array element with a sequence."
g = 9.81
theta = 30
dt = 0.1
t = 5
n = int(t/dt)
t = zeros(n)
r = zeros((n, 2), float)
v = zeros((n, 2), float)
a = zeros((n, 2), float)
r[0] = array([0,0])
v[0] = array([10*cos(theta), 10*sin(theta)])
t[0] = 0
for i in range(n-1):
v[i+1] = v[0] - g*dt
r[i+1] = r[i] + v[i]*dt
t[i+1] = t[i] + dt
The inserted code shows two columns (v[x,y] and r[x,y]) with different values, where only the y coordinate is correct. This is because the x coordinate is supposed to be constant. I don't understand how to make the x coordinate constant, and only do the operation on the y coordinate. I want the result to be calculated as:
v[i+1] = v[0] # x-coordinate
v[i+1] = v[0] - g*dt # y-coordinate
you need to only index the y part like this
v[i+1, 1] = v[i,1] - g*dt

Optimization of loop for circular matrices operations

I have a vector X_k and a matrix Y_{k,j}, where k = (k,...,K) and j = (1, .. J). They are circular, that means that
X_{k+K} = X_k, Y_{k+K,j} = Y_{k,j} and Y_{k,j+J} = Y_{k,j}
I want to compute a Zx vector and Zy matrix according to the following expressions:
Zx = -X_{k-1}*(X_{K-2}-X_{K+1})-X_k
Zy = -Y_{k,j+1}*(Y_{k,j+2}-Y_{k,j-1})-Y_{k,j}+X_k
Currently, I'm doing this through a loop, where first I compute the edge cases (for X: k = 1, 2, K. For Y: j = 1, J, J-1). And for the others, I use the formula.
I'm wondering if this calculus can be vectorized. Here is the example code.
import numpy as np
np.random.seed(10)
K = 20
J = 10
# initial state (equilibrium)
x = np.random.uniform(size=K)
y = np.random.uniform(size=(K*J))
y = y.reshape(K,J)
# zy
zy = np.zeros((K*J))
zy = zy.reshape(K,J)
# Edge case of Y
for k in range(K):
zy[k,0] = -y[k,1]*(y[k,2]-y[k,J-1])-y[k,0]+ x[k]
zy[k,J-1] = -y[k,0]*(y[k,1]-y[k,J-2])-y[k,J-1]+ x[k]
zy[k,J-2] = -y[k,J-1]*(y[k,0]-y[k,J-3])-y[k,J-2]+ x[k]
# General Case of Y
for j in range(1,J-2):
zy[k,j] = -y[k,j+1]*(y[k,j+2]-y[k,j-1])-y[k,j]+ x[k]
# zx
zx = np.zeros(K)
# first the 3 edge cases: k = 1, 2, K
zx[0] = -x[K-1]*(-x[1] + x[K-2]) - x[0]
zx[1] = - x[0]*(-x[2] + x[K-1])- x[1]
zx[K-1] = -x[K-2]*(-x[0] + x[K-3]) - x[K-1]
# then the general case for X
for k in range(2, K-1)
zx[k] = -x[k-1]*(-x[k+1] + x[k-2]) - x[k]
print(zx)
print(zy)
I suspect that is possible to optimize with matrix operations but not sure if it is possible without the loops (at least for the edge cases).
From Code Review I get the correct answer. The way to vectorize this kind of operation is through np.roll().
For example, the Y variable would be:
zy = np.roll(y,-1,axis=1)*(np.roll(y,-2,axis=1)-np.roll(y,1,axis=1))- y +x[:,None]

Way to solve constraint satisfaction faster than brute force?

I have a CSV that provides a y value for three different x values for each row. When read into a pandas DataFrame, it looks like this:
5 10 20
0 -13.6 -10.7 -10.3
1 -14.1 -11.2 -10.8
2 -12.3 -9.4 -9.0
That is, for row 0, at 5 the value is -13.6, at 10 the value is -10.7, and at 20 the value is -10.3. These values are the result of an algorithm in the form:
def calc(x, r, b, c, d):
if x < 10:
y = (x * r + b) / x
elif x >= 10 and x < 20:
y = ((x * r) + (b - c)) / x
else:
y = ((x * r) + (b - d)) / x
return y
I want to find the value of r, b, c, and d for each row. I know certain things about each of the values. For example, for each row: r is in np.arange(-.05, -.11, -.01), b is in np.arange(0, -20.05, -.05), and c and d are in np.arange(0, 85, 5). I also know that d is <= c.
Currently, I am solving this with brute force. For each row, I iterate through every combination of r, b, c, and d and test if the value at the three x values is equal to the known value from the DataFrame. This works, giving me a few combinations for each row that are basically the same except for rounding differences.
The problem is that this approach takes a long time when I need to run it against 2,000+ rows. My question is: is there a faster way than iterating and testing every combination? My understanding is that this is a constraint satisfaction problem but, after that, I have no idea what to narrow in on; there are so many types of constraint satisfaction problems (it seems) that I'm still lost (I'm not even certain that this is such a problem!). Any help in pointing me in the right direction would be greatly appreciated.
I hope i understood the task correctly.
If you know the resolution/discretization of the parameters, it looks like a discrete-optimization problem (in general: hard), which could be solved by CP-approaches.
But if you allow these values to be continuous (and reformulate the formulas), it is:
(1) a Linear Program: if checking for feasible values (there needs to be a valid solution)
(2) a Linear Program: if optimizing parameters for minimization of sum of absolute differences (=errors)
(3) a Quadratic Program: if optimizing parameters for minimization of sum of squared differences (=errors) / equivalent to minimizing euclidean-norm
All three versions can be solved efficiently!
Here is a non-general (could be easily generalized) implementation of (3) using cvxpy to formulate the problem and ecos to solve the QP. Both tools are open-source.
Code
import numpy as np
import time
from cvxpy import *
from random import uniform
""" GENERATE TEST DATA """
def sample_params():
while True:
r = uniform(-0.11, -0.05)
b = uniform(-20.05, 0)
c = uniform(0, 85)
d = uniform(0, 85)
if d <= c:
return r, b, c, d
def calc(x, r, b, c, d):
if x < 10:
y = (x * r + b) / x
elif x >= 10 and x < 20:
y = ((x * r) + (b - c)) / x
else:
y = ((x * r) + (b - d)) / x
return y
N = 2000
sampled_params = [sample_params() for i in range(N)]
data_5 = np.array([calc(5, *sampled_params[i]) for i in range(N)])
data_10 = np.array([calc(10, *sampled_params[i]) for i in range(N)])
data_20 = np.array([calc(20, *sampled_params[i]) for i in range(N)])
data = np.empty((N, 3))
for i in range(N):
data[i, :] = [data_5[i], data_10[i], data_20[i]]
""" SOLVER """
def solve(row):
""" vars """
R = Variable(1)
B = Variable(1)
C = Variable(1)
D = Variable(1)
E = Variable(3)
""" constraints """
constraints = []
# bounds
constraints.append(R >= -.11)
constraints.append(R <= -.05)
constraints.append(B >= -20.05)
constraints.append(B <= 0.0)
constraints.append(C >= 0.0)
constraints.append(C <= 85.0)
constraints.append(D >= 0.0)
constraints.append(D <= 85.0)
constraints.append(D <= C)
# formula of model
constraints.append((1.0 / 5.0) * B + R == row[0] + E[0]) # alternate function form: b/x+r
constraints.append((1.0 / 10.0) * B - (1.0 / 10.0) * C == row[1] + E[1]) # alternate function form: b/x-c/x+r
constraints.append((1.0 / 20.0) * B - (1.0 / 20.0) * D == row[2] + E[2]) # alternate function form: b/x-d/x+r
""" Objective """
objective = Minimize(norm(E, 2))
""" Solve """
problem = Problem(objective, constraints)
problem.solve(solver=ECOS, verbose=False)
return R.value, B.value, C.value, D.value, E.value
start = time.time()
for i in range(N):
r, b, c, d, e = solve(data[i])
end = time.time()
print('seconds taken: ', end-start)
print('seconds per row: ', (end-start) / N)
Output
('seconds taken: ', 20.620506048202515)
('seconds per row: ', 0.010310253024101258)

Karatsuba algorithm too much recursion

I am trying to implement the Karatsuba multiplication algorithm in c++ but right now I am just trying to get it to work in python.
Here is my code:
def mult(x, y, b, m):
if max(x, y) < b:
return x * y
bm = pow(b, m)
x0 = x / bm
x1 = x % bm
y0 = y / bm
y1 = y % bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
What I don't get is: how should z2, z1, and z0 be created? Is using the mult function recursively correct? If so, I'm messing up somewhere because the recursion isn't stopping.
Can someone point out where the error is?
NB: the response below addresses directly the OP's question about
excessive recursion, but it does not attempt to provide a correct
Karatsuba algorithm. The other responses are far more informative in
this regard.
Try this version:
def mult(x, y, b, m):
bm = pow(b, m)
if min(x, y) <= bm:
return x * y
# NOTE the following 4 lines
x0 = x % bm
x1 = x / bm
y0 = y % bm
y1 = y / bm
z0 = mult(x0, y0, b, m)
z2 = mult(x1, y1, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
retval = mult(mult(z2, bm, b, m) + z1, bm, b, m) + z0
assert retval == x * y, "%d * %d == %d != %d" % (x, y, x * y, retval)
return retval
The most serious problem with your version is that your calculations of x0 and x1, and of y0 and y1 are flipped. Also, the algorithm's derivation does not hold if x1 and y1 are 0, because in this case, a factorization step becomes invalid. Therefore, you must avoid this possibility by ensuring that both x and y are greater than b**m.
EDIT: fixed a typo in the code; added clarifications
EDIT2:
To be clearer, commenting directly on your original version:
def mult(x, y, b, m):
# The termination condition will never be true when the recursive
# call is either
# mult(z2, bm ** 2, b, m)
# or mult(z1, bm, b, m)
#
# Since every recursive call leads to one of the above, you have an
# infinite recursion condition.
if max(x, y) < b:
return x * y
bm = pow(b, m)
# Even without the recursion problem, the next four lines are wrong
x0 = x / bm # RHS should be x % bm
x1 = x % bm # RHS should be x / bm
y0 = y / bm # RHS should be y % bm
y1 = y % bm # RHS should be y / bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
Usually big numbers are stored as arrays of integers. Each integer represents one digit. This approach allows to multiply any number by the power of base with simple left shift of the array.
Here is my list-based implementation (may contain bugs):
def normalize(l,b):
over = 0
for i,x in enumerate(l):
over,l[i] = divmod(x+over,b)
if over: l.append(over)
return l
def sum_lists(x,y,b):
l = min(len(x),len(y))
res = map(operator.add,x[:l],y[:l])
if len(x) > l: res.extend(x[l:])
else: res.extend(y[l:])
return normalize(res,b)
def sub_lists(x,y,b):
res = map(operator.sub,x[:len(y)],y)
res.extend(x[len(y):])
return normalize(res,b)
def lshift(x,n):
if len(x) > 1 or len(x) == 1 and x[0] != 0:
return [0 for i in range(n)] + x
else: return x
def mult_lists(x,y,b):
if min(len(x),len(y)) == 0: return [0]
m = max(len(x),len(y))
if (m == 1): return normalize([x[0]*y[0]],b)
else: m >>= 1
x0,x1 = x[:m],x[m:]
y0,y1 = y[:m],y[m:]
z0 = mult_lists(x0,y0,b)
z1 = mult_lists(x1,y1,b)
z2 = mult_lists(sum_lists(x0,x1,b),sum_lists(y0,y1,b),b)
t1 = lshift(sub_lists(z2,sum_lists(z1,z0,b),b),m)
t2 = lshift(z1,m*2)
return sum_lists(sum_lists(z0,t1,b),t2,b)
sum_lists and sub_lists returns unnormalized result - single digit can be greater than the base value. normalize function solved this problem.
All functions expect to get list of digits in the reverse order. For example 12 in base 10 should be written as [2,1]. Lets take a square of 9987654321.
» a = [1,2,3,4,5,6,7,8,9]
» res = mult_lists(a,a,10)
» res.reverse()
» res
[9, 7, 5, 4, 6, 1, 0, 5, 7, 7, 8, 9, 9, 7, 1, 0, 4, 1]
The goal of the Karatsuba multiplication is to improve on the divide-and conquer multiplication algorithm by making 3 recursive calls instead of four. Therefore, the only lines in your script that should contain a recursive call to the multiplication are those assigning z0,z1 and z2. Anything else will give you a worse complexity. You can't use pow to compute bm when you haven't defined multiplication yet (and a fortiori exponentiation), either.
For that, the algorithm crucially uses the fact that it is using a positional notation system. If you have a representation x of a number in base b, then x*bm is simply obtained by shifting the digits of that representation m times to the left. That shifting operation is essentially "free" with any positional notation system. That also means that if you want to implement that, you have to reproduce this positional notation, and the "free" shift. Either you chose to compute in base b=2 and use python's bit operators (or the bit operators of a given decimal, hex, ... base if your test platform has them), or you decide to implement for educational purposes something that works for an arbitrary b, and you reproduce this positional arithmetic with something like strings, arrays, or lists.
You have a solution with lists already. I like to work with strings in python, since int(s, base) will give you the integer corresponding to the string s seen as a number representation in base base: it makes tests easy. I have posted an heavily commented string-based implementation as a gist here, including string-to-number and number-to-string primitives for good measure.
You can test it by providing padded strings with the base and their (equal) length as arguments to mult:
In [169]: mult("987654321","987654321",10,9)
Out[169]: '966551847789971041'
If you don't want to figure out the padding or count string lengths, a padding function can do it for you:
In [170]: padding("987654321","2")
Out[170]: ('987654321', '000000002', 9)
And of course it works with b>10:
In [171]: mult('987654321', '000000002', 16, 9)
Out[171]: '130eca8642'
(Check with wolfram alpha)
I believe that the idea behind the technique is that the zi terms are computed using the recursive algorithm, but the results are not unified together that way. Since the net result that you want is
z0 B^2m + z1 B^m + z2
Assuming that you choose a suitable value of B (say, 2) you can compute B^m without doing any multiplications. For example, when using B = 2, you can compute B^m using bit shifts rather than multiplications. This means that the last step can be done without doing any multiplications at all.
One more thing - I noticed that you've picked a fixed value of m for the whole algorithm. Typically, you would implement this algorithm by having m always be a value such that B^m is half the number of digits in x and y when they are written in base B. If you're using powers of two, this would be done by picking m = ceil((log x) / 2).
Hope this helps!
In Python 2.7: Save this file as Karatsuba.py
def karatsuba(x,y):
"""Karatsuba multiplication algorithm.
Return the product of two numbers in an efficient manner
#author Shashank
date: 23-09-2018
Parameters
----------
x : int
First Number
y : int
Second Number
Returns
-------
prod : int
The product of two numbers
Examples
--------
>>> import Karatsuba.karatsuba
>>> a = 1234567899876543211234567899876543211234567899876543211234567890
>>> b = 9876543211234567899876543211234567899876543211234567899876543210
>>> Karatsuba.karatsuba(a,b)
12193263210333790590595945731931108068998628253528425547401310676055479323014784354458161844612101832860844366209419311263526900
"""
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
n = max(len(str(x)), len(str(y)))
m = n/2
a = x/10**m
b = x%10**m
c = y/10**m
d = y%10**m
ac = karatsuba(a,c) #step 1
bd = karatsuba(b,d) #step 2
ad_plus_bc = karatsuba(a+b, c+d) - ac - bd #step 3
prod = ac*10**(2*m) + bd + ad_plus_bc*10**m #step 4
return prod

Categories