How do I run this function for multiple values of N? - python

I am trying to run the code below for N = np.linspace(20,250,47), but I get multiple errors when trying to change the N. I am new to python and am not sure how to get multiple values of this function using multiple values of N. Below is the code with N = 400 and it does work, but I am not sure how to make it work for multiple N's at the same time.
import matplotlib.pyplot as plt
import numpy as np
S0 = 9
K = 10
T = 3
r = 0.06
sigma = 0.3
N = 400
dt = T / N
u = exp(sigma*sqrt(dt)+(r-0.5*sigma**2)*dt)
d = exp(-sigma*sqrt(dt)+(r-0.5*sigma**2)*dt)
p = 0.5
def binomial_tree_put(N, T, S0, sigma, r, K, array_out=False):
dt = T / N
u = exp(sigma*sqrt(dt)+(r-0.5*sigma**2)*dt)
d = exp(-sigma*sqrt(dt)+(r-0.5*sigma**2)*dt)
p = 0.5
price_tree = np.zeros([N+1,N+1])
for i in range(N+1):
for j in range(i+1):
price_tree[j,i] = S0*(d**j)*(u**(i-j))
option = np.zeros([N+1,N+1])
option[:,N] = np.maximum(np.zeros(N+1), K - price_tree[:,N])
for i in np.arange(N-1, -1, -1):
for j in np.arange(0, i+1):
option[j, i] = np.exp(-r*dt)*(p*option[j, i+1]+(1-p)*option[j+1, i+1])
if array_out:
return [option[0,0], price_tree, option]
else:
return option[0,0]

Suppose you have a list of values for N e.g N = [400, 300, 500, 800], then you need to call the function for every value, you can use a loop for that.
For example,
for num in N:
binomial_tree_put(num, *other arguments*)

np.linspace() creates an np.array but the function expects a sinlge integer. If you want to execute a function for each element contained inside a array/list, you can do that inside a loop like this:
# your code as defined above goes here
for num in np.linspace(20,250,47):
N = int(num) # you could just put N in the line above - this is just to illustrate
binomial_tree_put(N, T, S0, sigma, r, K, array_out=False)
Be aware, depending on how long your function takes to execute and how many elements are in your iterable (e.g. 47 for your case), it may take a while to execute.
Edit: I also noticed you seem to be missing an import in your example code. exp() and sqrt() are part of the math module.

You can also use partial function, like this:
from functools import partial
N = [1, 2, ...] # all your N values
binom_fct = partial(binomial_tree_put, T=T, S0=S0, sigma=sigma, r=r, K=K, array_out=array_out)
for num in N:
binom_fct(num)
partial help here

Related

This is a random 3-cnf generator, can i make this k-cnf (k literals per clause), I want want to give k as a parameter so i can change it

As you can see this is a function that creates random 3-cnf problems. Given the number of literals and clauses, returns a randomly generated 3-CNF sentence composed of clauses in the form of horn clauses(i used a git library that can transform python code into prolog code). I want this to be k-cnf where i can pass k as a parameter, so if I say k: 3 i get 3-cnf, or k:5 i get 5-cnf. Additionally, i like the numbers to be a character like x1, x2, x2 etc instead of numbers. Is this possible? Thanks in advance :)
def tcnfgen(m, k, horn=1):
cnf = []
def unique(l, k):
t = random.randint(1, k)
while (t in l):
t = random.randint(1, k)
return t
r = (lambda: random.randint(0, 1))
for i in range(m):
x = unique([], k)
y = unique([x], k)
z = unique([x, y], k)
if horn:
cnf.append(Program(P.head(x) <= (P.body(y), P.body(z)))) #horn clauses; head positive, body negative
else:
cnf.append([x, r(), y, r(), z, r()])
return cnf

Calculation of a symbolic expression in SymPy and convert them to numeric within Julia

I am trying to convert a piece of python code to Julia 1.1.0.
The python code:
import numpy as np
import sympy as sp
x, y = sp.symbols('x y')
data = np.random.randn(1000, 2)
a,b = data[:,0], data[:,1]
M = len(data[:,0])
m = 5
n = round(m*(m+1)/2)
L = np.zeros((M,n))
l = sp.zeros(1,n)
k = 0
for i in range(1,m+1):
for j in range(1,i+1):
l[0,k]=((i-j)*(i-j-1)*x**(i-j-2)*y**(j-1))
f = sp.lambdify([x,y], l[0,k], "numpy")
L[:,k] = np.squeeze(f(a,b))
k=k+1
and my attempt of Julia code:
using SymPy
data = rand(1000,2)
a = data[:,1];
b = data[:,2];
M = length(data[:,1])
x = symbols("x");
y = symbols("y");
m = 5;
n = Int(m*(m+1)/2)
L = zeros(M,n)
l = zeros(1,n)
k = 1;
for i in 1:m
for j in 1:i
l[1,k] = ((i-j)*(i-j-1)*x^(i-j-2)*y^(j-1))
f = l[1,k]
L[:,k] = f.subs([(x, a), (y, b)])
k=k+1
end
end
when I runJulia codes, for l[1,k] I got following error
DomainError with -2:
Cannot raise an integer x to a negative power -2.
Convert input to float.
Stacktrace:
[1] throw_domerr_powbysq(::Sym, ::Int64) at ./intfuncs.jl:173
[2] power_by_squaring(::Sym, ::Int64) at ./intfuncs.jl:196
[3] ^(::Sym, ::Int64) at ./intfuncs.jl:221
[4] top-level scope at ./In[80]:14
Also, I am not sure about the following codes
f = l[1,k]
L[:,k] = f.subs([(x, a), (y, b)])
I would appreciate if someone can help me to translate python codes to julia codes.
Update:
Based on the post of #jverzani I can now convert sym values to float with following codes
using SymPy
data = rand(1000,2)
a = data[:,1];
b = data[:,2];
M = length(data[:,1])
x = symbols("x");
y = symbols("y");
m = 5;
n = Int(m*(m+1)/2)
LL = zeros(M,n)
L = zeros(Sym, M,n)
l = zeros(Sym, 1,n)
k = 1;
for i in 1:m
for j in 1:i
l[1,k] = ((i-j)*(i-j-1)*x^Sym(i-j-2)*y^Sym(j-1))
f = l[1,k]
L[:,k] .= f.subs([(x, a), (y, b)])
global k=k+1
end
end
for s in 1:M
for r in 1:n
LL[s,r] = float(subs(L[s,r],(x,a[s]),(y,b[s])))
end
end
But this time the codes are very slow. How can I optimize the codes.
SymPy just got a major change, inherited from PyCall, which makes the last bit with subs work as typed.
As for the first one, you are bumping into a Julia issue with integer bases and non-literal, negative integer powers. You can modify that line to make the powers symbolic, such as x^Sym(i-j-2) in place of x^(i-j-2). (It might be best to bypass this.)
The following edit tries to mirror the spirit of the Python code. It wraps into a function to test speed on size of N and avoid the need for global on the k assignment.
using SymPy
import PyCall
np = PyCall.pyimport("numpy") #import numpy as np
const sp = sympy
function fill_L(N=1000)
x, y = sp.symbols("x y")
offset = 1
data = np.random.randn(N, 2)
a,b = data[:,0+offset], data[:,1+offset]
M = length(data[:,0+offset])
m = 5
n = round(Int, m*(m+1)/2)
L = np.zeros((M,n))
l = sp.zeros(1,n)
k = 0
for i in 1:m
for j in 1:i
l[1,k+offset]=((i-j)*Sym(i-j-1)*x^Sym(i-j-2)*y^Sym(j-1))
f = lambdify(l[1,k+offset], (x, y))
#f = sp.lambdify([x,y], l[0,k], "numpy")
L[:,k+offset] = f.(a,b)
k=k+1
end
end
L
end
Performance is reasonable now, due to the broadcasting of f above.

itertools combinations in tandem with looping

I have the following Python code. Because random is being used, it generates a new answer every time:
import random
import numpy as np
N = 64 # Given
T = 5 # Given
FinalLengths = []
for i in range(T):
c = range(1, N)
x = random.sample(c, 2) # Choose 2 random numbers between 1 and N-1
LrgstNode = max(x)
SmlstNode = min(x)
RopeLengths = [SmlstNode, LrgstNode - SmlstNode, N - LrgstNode]
S = max(RopeLengths)
N = S
FinalLengths.append(S)
avgS = np.mean(FinalLengths) # Find average
print("The mean of S is {}".format(avgS))
My research has led me to possibly using itertools combinations in order to produce all possible combinations within the range and get the avg to converge. If so, how?
Thank you.
It sounds like you're after something like this:
import random
import numpy as np
from itertools import combinations
N = 64 # Given
T = 5 # Given
FinalLengths = []
for i in range(T):
c = list(range(1, N))
for x in combinations(c, 2):
S = max([min(x), max(x) - min(x), N - max(x)])
N = S
FinalLengths.append(S)
avgS = np.mean(FinalLengths) # Find average
print("The mean of S is {}".format(avgS))
To use combinations(l, size) we can pass in a list l and the size of each combination tuple, and int size. That's all there is to it!

How to minimize code when there are lot of lists?

I'm making a code to simulate a Brownian motion.
from random import random
import matplotlib.pyplot as plt
import numpy as np
N=100
p=0.5
l=1
x1=[]
x2=[]
x1.append(0)
x2.append(0)
for i in range(1, N):
step = -l if random() < p else l
X1 = x1[i-l] + step
x1.append(X1)
for i in range(1, N):
step = -l if random() < p else l
X2 = x2[i-l] + step
x2.append(X2)
x1mean=np.array(x1)
x2mean=np.array(x2)
mean=[]
for j in range (0,N):
mean.append((x1mean[j]+x2mean[j])/2.0)
plt.plot(mean)
plt.plot(x1)
plt.plot(x2)
plt.show()
This code makes the displacement for 2 diferent particles, but in order to calculate the mean displacement properly, I would need to have a great number of particles, likes 100. As you can see, I'm looking for a way to condensate the code because I cannot repetat the same code 100 times.
Is there a way to create a loop that makes all this code in function of 1 variable, i.e. the number of particles?
Thanks.
I can't provide you a working python code, because until now I did not write a single line of python code. But I can give you an idea how to solve your problem.
Assumptions:
N : Number of Moves
P : Number of Particles
Step 1:
Create a method generating your array/list and returning it. So you can re-use it and avoid copying your code.
def createParticleMotion(N, p, l):
x1=[]
x1.append(0)
for i in range(1, N):
step = -l if random() < p else l
X1 = x1[i-l] + step
x1.append(X1)
return x1
Step 2:
Create a list of lists, lets call it particleMotions. The list it selves has P list of your N moves. Fill the list within a for loop for you number of particles P by calling the method from the first step and append the list paticleMotions by the returned list/array.
May be the answer for Python: list of lists will help you creating this.
Step 3:
After you created and filled particleMotions use this list within a double for loop and calculate the mean and store it in a list of means.
mean=[]
for n in range (0,N):
sum=0
for p in range (0,P):
sum = sum + particleMotions[p][n]
mean.append(sum/P)
And now you can use a next for loop to plot your result.
for particle in range (0,P):
plt.plot(particleMotions[particle])
So again don't blame me for syntax errors. I am no phyton developer. I just want to give you a way to solve your problem.
This?
from random import random
import matplotlib.pyplot as plt
import numpy as np
N=100
p=0.5
l=1
mydict = {}
for n in range(100):
mydict[n] = []
mydict[n].append(0)
for i in range(1, N):
step = -l if random() < p else l
X1 = mydict[n][i-l] + step
mydict[n].append(X1)
for k,v in mydict.iteritems():
plt.plot(v)
# mean
plt.plot([np.mean(i) for i in mydict.values()])
plt.show()

How to do numerical integration in python?

I can't install anything new I need to use the default python library and I have to integrate a function. I can get the value for any f(x) and I need to integrate from 0 to 6 for my function f(x).
In discrete form, integration is just summation, i.e.
where n is the number of samples. If we let b-a/n be dx (the 'width' of our sample) then we can write this in python as such:
def integrate(f, a, b, dx=0.1):
i = a
s = 0
while i <= b:
s += f(i)*dx
i += dx
return s
Note that we make use of higher-order functions here. Specifically, f is a function that is passed to integrate. a, b are our bounds and dx is 1/10 by default. This allows us to apply our new integration function to any function we wish, like so:
# the linear function, y = x
def linear(x):
return x
integrate(linear, 1, 6) // output: 17.85
# or using lamdba function we can write it directly in the argument
# here is the quadratic function, y=x^2
integrate(lambda x: x**2, 0, 10) // output: 338.35
You can use quadpy (out of my zoo of packages):
import numpy
import quadpy
def f(x):
return numpy.sin(x) - x
val, err = quadpy.quad(f, 0.0, 6.0)
print(val)
-17.96017028290743
def func():
print "F(x) = 2x + 3"
x = int(raw_input('Enter an integer value for x: '))
Fx = 2 * x + 3
return Fx
print func()
using the input function in python, you can randomly enter any number you want and get the function or if hard coding this this necessary you can use a for loop and append the numbers to a list for example
def func2():
print "F(x) = 2x + 3"
x = []
for numbers in range(1,7):
x.append(numbers)
upd = 0
for i in x:
Fx = 2 * x[upd] + 3
upd +=1
print Fx
print func2()
EDIT: if you would like the numbers to start counting from 0 set the first value in range to 0 instead of 1

Categories