After having tried many things, I thought it would be good to ask on SO. My problem is fairly simple: how can I solve the following equation using Sympy?
Equation
I want to solve this for lambda_0 and q is an array of size J containing elments between 0 and 1 that sum op to 1 (discrete probability distribution). I tried the following:
from sympy.solvers import solve
from sympy import symbols, summation
p = [0.2, 0.3, 0.3, 0.1, 0.1]
l = symbols('l')
j = symbols('j')
eq= summation(j*q[j]/(l-j), (j, 0, 4))
s= solve(eq, l)
But this gives me an error for q[j] as j is a Symbol object here and not an integer. If I don't make j as symbol, I cannot evaluate the eq expression. Does anyone know how to do this?
Edit: p = 1-q in the above, hence q[j] should have been replaced by (1-p[j]).
List p needs to be converted into symbolic array before it can be indexed with symbolic value j.
from sympy.solvers import solve
from sympy import symbols, summation, Array
p = Array([0.2, 0.3, 0.3, 0.1, 0.1])
l, j = symbols('l j')
eq = summation(j * (1 - p[j]) / (l - j), (j, 0, 4))
s = solve(eq - 1, l) # [1.13175762143963 + 9.29204634892077e-30*I, 2.23358705810004 - 1.36185313905566e-29*I, 3.4387382449005 + 3.71056356734273e-30*I, 11.5959170755598 + 6.15921474293073e-31*I]
(assuming your p stands for 1 - q)
Related
I was trying to differentiate this equation with respect to time using sympy, where the angles theta_k, theta_i etc are functions of time but when summing them up I need to be able to refence them in the summation using their indices.
For example Sum(theta(k), (k, 1, i)) = theta(1) + theta(2) + ... + theta(n), but I don't quite get how to write that theta(k) part in the code
from sympy import *
from latex2sympy2 import latex2sympy
init_printing()
m, L, g, n, i, k, t, t_0 = symbols("m L g n i k t t_0")
# m for mass, L for the length of the string, g for gravity,
# n, i and k are indices
# n = int(input("Enter the number of bobs: "))
n = 6
tp = IndexedBase('tp')
t = IndexedBase('t')
Lg_tex = r'\frac{1}{2} m L^2 \sum_{i=1}^n\left(\left(\sum_{k=1}^i \dot{\theta_k} \cos \left(\theta_k\right)\right)^2+\left(\sum_{k=1}^i \dot{\theta_k} \sin \left(\theta_k\right)\right)^2\right)+m g L\left(\sum_{i=1}^n \cos \left(\theta_i\right)\right)'
Lg = latex2sympy(Lg_tex)
Lg_sympy = (1/2)*m*L**2*Sum(Sum(tp[k]*sin(t[k]), (k, 1, i)).doit()**2 + Sum(tp[k]*cos(t[k]), (k, 1, i)).doit()**2, (i, 1, n)).doit() + m*g*L*Sum(cos(t[k]), (i, 1, n)).doit()
# The Euler-Lagrange equation has two parts,
# I'm gonna consider the LHS as the shorter side and the RHS as the longer side
Lagrangian_LHS = []
Lagrangian_RHS = []
solutions = [] # The elements of this array are the equations for each of the accelerations
for i in range(n):
LHS = diff(Lg_sympy, t[i + 1])
Lagrangian_LHS.append(LHS)
RHS = diff(Lg_sympy, tp[i + 1])
tp = Function('tp')(t_0)
RHS = diff(RHS, t_0)
tp = IndexedBase('tp')
Lagrangian_RHS.append(RHS)
What I tried to do was I first defined the angles as normal variables that can be indexed and after I summed them up I turned them into functions and then after differentiating them I turned them back into regular indexed variables but that approach is also throwing errors at me saying that functions can't be subscripted
tldr: I want to differentiate the terms inside a summation which are functions in sympy
Is there some efficient way to "double vectorize" a Numpy function?
Consider some function f which is vectorized over its first 3 positional arguments; its implementation consists entirely of Numpy vectorized functions (arithmetic, trigonometry, et alia) which correctly implement broadcasting.
The first two arguments of f are x and y, which represent some kind of input data. Its 3rd argument q is a parameter that controls some aspect of the computation.
In my program, I have the following:
Arrays x and y that are 1-d arrays of the same length. x[i] and y[i] correspond to the ith data point in a dataset.
Array q which is a 1-d array of different length. q[k] corresponds to some kth data point in a different collection.
I want to compute the value of f(x[i], y[i], q[k]) for any pair i, k, collecting the results in a matrix.
That is, I want to perform a vectorized version of the following calculation:
result = np.empty((len(x), len(q))
for k in range(len(q)):
for i in range(len(x)):
result[i, k] = f(x[i], y[i], q[k])
The "singly-vectorized" version (over the i index) would be:
result = np.empty((len(x), len(q))
for k in range(len(q)):
result[:, k] = f(x, y, q[k])
And this is what I currently use in my code.
Is there an efficient way to vectorize over both indexes, maybe using some broadcasting trick?
As an example of such a function f, consider the Law of Cosines:
def law_of_cosines(a, b, ϑ):
return np.sqrt(
np.square(a) +
np.square(b) +
2.0 * a * b * np.cos(ϑ)
)
Depending on the actual f, I think I'd approach it like...
# set up example variables
N, M = 11, 13
x = np.random.normal(N)
y = np.random.normal(N)
q = np.random.normal(M)
# reshape for broadcasting
X = x[:, np.newaxis]
Y = y[:, np.newaxis]
Q = q[np.newaxis, :]
f(X, Y, Q)
then if f is, I lack the proper term for it, ufunc-like, it should broadcast nicely. If it isn't, and it's hard to tell without the actual "a bit complicated" implementation", you could make it so either via changing the implementation or possibly by numba's vectorize decorator, which is how I usually do that.
You can vectorise the second "vectorised" multiplication operation using np.outer. It contains no for loops.
The following code contains a print statement with the "double-vectorised" version. I also fixed the minor typo in brackets in the creation of the empty results matrix.
import numpy as np
x = [0.1, 0.2, 0.3]
y = [0.4, 0.6, 0.8]
q = [0.4, 0.5, 0.6, 0.7]
result = np.empty((len(x),len(q)))
for k in range(len(q)):
for i in range(len(x)):
result[i, k] = np.arctan2(x[i], y[i]) * q[k]
print(result)
print(np.outer(np.arctan2(x, y) , q))
Results:
[[0.09799147 0.12248933 0.1469872 0.17148506]
[0.12870022 0.16087528 0.19305033 0.22522539]
[0.14350827 0.17938534 0.2152624 0.25113947]]
[[0.09799147 0.12248933 0.1469872 0.17148506]
[0.12870022 0.16087528 0.19305033 0.22522539]
[0.14350827 0.17938534 0.2152624 0.25113947]]
Hope this helps.
I am trying to calculate the logarithmic maximum of n different bets. However, for this example, I have 2 independent simultaneous bets.
Bet 1 has a win probability of 30% and decimal odds of 12.80.
Bet 2 also has a win probability of 30% and decimal odds of 12.80.
To calculate the logarithmic maximum of 2 independent simultaneous bets, I need to work out the probability of all 4 combinations:
Bet 1 Winning/Bet 2 Winning
Bet 1 Winning/Bet 2 Losing
Bet 1 Losing/Bet 2 Winning
Bet 1 Losing/Bet 2 Losing
Assuming x0 is the amount between 0% and 100% of my portfolio on Bet 1 and x1 is the amount between 0% and 100% of my portfolio on Bet 2, the mathematically optimum stakes on both bets can be solved by maximising the following expression:
0.09log(1 + 11.8x0 + 11.8x1) + 0.21log(1 + 11.8x0 - x1) + 0.21log(1 - x0 + 11.8x1) + 0.49log(1 - x0 - x1) which equals x0: 0.214648, x1: 0.214648
(The 11.8 is not a typo, it is simply 12.8 - 1, the profit).
I have tried to implement this calculation in python, with little success. Here is my current code that I need assistance with:
from scipy.optimize import minimize
from math import log
from itertools import product
from sympy import symbols
Bets = [[0.3, 12.8], [0.3, 12.8]]
Odds = [([i[0], 1 - i[0]]) for i in Bets]
OddsList = list(product(Odds[0], Odds[1]))
#Output [(0.3, 0.3), (0.3, 0.7), (0.7, 0.3), (0.7, 0.7)]
Probability = []
for i in range(0, len(OddsList)):
Probability.append(OddsList[i][0] * OddsList[i][1])
#Output [0.09, 0.21, 0.21, 0.49]
Win = [([i[1] - 1, - 1]) for i in Bets]
WinList = list(product(Win[0], Win[1]))
#Output [(11.8, 11.8), (11.8, -1), (-1, 11.8), (-1, -1)]
xValues = []
for j in range(0, len(Bets)):
xValues.append(symbols('x' + str(j)))
#Output [x0, x1]
def logarithmic_return(xValues, Probability, WinList):
Sum = 0
for i in range(0, len(Probability)):
Sum += Probability[i] * log (1 + (WinList[i][0] * xValues[0]) + ((WinList[i][1] * xValues[1])))
return Sum
minimize(logarithmic_return(xValues, Probability, WinList))
#Error TypeError: Cannot convert expression to float
# However, when I do this, it works perfectly:
logarithmic_return([0.214648, 0.214648], Probability, WinList)
#Output 0.3911621722324154
Seems like this is your first time mixing numerical Python with symbolic. In short, you cannot use numerical functions (like math.log or scipy.optimize.minimize) on symbolic expressions. You need to convert your symbolic expressions to lambda function first.
Let's try to fix it:
from scipy.optimize import minimize
from itertools import product
from sympy import symbols, lambdify, log
import numpy as np
Bets = [[0.3, 12.8], [0.3, 12.8]]
Odds = [([i[0], 1 - i[0]]) for i in Bets]
OddsList = list(product(Odds[0], Odds[1]))
#Output [(0.3, 0.3), (0.3, 0.7), (0.7, 0.3), (0.7, 0.7)]
Probability = []
for i in range(0, len(OddsList)):
Probability.append(OddsList[i][0] * OddsList[i][1])
#Output [0.09, 0.21, 0.21, 0.49]
Win = [([i[1] - 1, - 1]) for i in Bets]
WinList = list(product(Win[0], Win[1]))
#Output [(11.8, 11.8), (11.8, -1), (-1, 11.8), (-1, -1)]
xValues = []
for j in range(0, len(Bets)):
xValues.append(symbols('x' + str(j)))
#Output [x0, x1]
def logarithmic_return(xValues, Probability, WinList):
Sum = 0
for i in range(0, len(Probability)):
Sum += Probability[i] * log (1 + (WinList[i][0] * xValues[0]) + ((WinList[i][1] * xValues[1])))
return Sum
# this is the symbolic expression
expr = logarithmic_return(xValues, Probability, WinList)
# convert the symbolic expression to a lambda function for
# numerical evaluation
f = lambdify(xValues, expr)
# minimize expect a function of the type f(x), not f(x0, x1).
# hence, we create a wrapper function
func_to_minimize = lambda x: f(x[0], x[1])
initial_guess = [0.5, 0.5]
minimize(func_to_minimize, initial_guess)
# fun: -inf
# hess_inv: array([[1, 0],
# [0, 1]])
# jac: array([nan, nan])
# message: 'NaN result encountered.'
# nfev: 3
# nit: 0
# njev: 1
# status: 3
# success: False
# x: array([0.5, 0.5])
As you can see, the minimization works. However it didn't find any solution. This is your problem to fix. Here, I just hint you the shape of the function you are trying to minimize.
The problem here is that scipy.optimize.minimize wants to be passed a function. You are not passing a function. You are CALLING your function, and passing its return (a float) to minimize.
You need:
minimize( logarithmic_return, xValues, args=(Probability, WinList) )
I am trying to find the minimum of a natural cubic spline. I have written the following code to find the natural cubic spline. (I have been given test data and have confirmed this method is correct.) Now I can not figure out how to find the minimum of this function.
This is the data
xdata = np.linspace(0.25, 2, 8)
ydata = 10**(-12) * np.array([1,2,1,2,3,1,1,2])
This is the function
import scipy as sp
import numpy as np
import math
from numpy.linalg import inv
from scipy.optimize import fmin_slsqp
from scipy.optimize import minimize, rosen, rosen_der
def phi(x, xd,yd):
n = len(xd)
h = np.array(xd[1:n] - xd[0:n-1])
f = np.divide(yd[1:n] - yd[0:(n-1)],h)
q = [0]*(n-2)
for i in range(n-2):
q[i] = 3*(f[i+1] - f[i])
A = np.zeros(((n-2),(n-2)))
#define A for j=0
A[0,0] = 2*(h[0] + h[1])
A[0,1] = h[1]
#define A for j = n-2
A[-1,-2] = h[-2]
A[-1,-1] = 2*(h[-2] + h[-1])
#define A for in the middle
for j in range(1,(n-3)):
A[j,j-1] = h[j]
A[j,j] = 2*(h[j] + h[j+1])
A[j,j+1] = h[j+1]
Ainv = inv(A)
B = Ainv.dot(q)
b = (n)*[0]
b[1:(n-1)] = B
# now we find a, b, c and d
a = [0]*(n-1)
c = [0]*(n-1)
d = [0]*(n-1)
s = [0]*(n-1)
for r in range(n-1):
a[r] = 1/(3*h[r]) * (b[r + 1] - b[r])
c[r] = f[r] - h[r]*((2*b[r] + b[r+1])/3)
d[r] = yd[r]
#solution 1 start
for m in range(n-1):
if xd[m] <= x <= xd[m+1]:
s = a[m]*(x - xd[m])**3 + b[m]*(x-xd[m])**2 + c[m]*(x-xd[m]) + d[m]
return(s)
#solution 1 end
I want to find the minimum on the domain of my xdata, so a fmin didn't work as you can not define bounds there. I tried both fmin_slsqp and minimize. They are not compatible with the phi function I wrote so I rewrote phi(x, xd,yd) and added an extra variable such that phi is phi(x, xd,yd, m). M indicates in which subfunction of the spline we are calculating a solution (from x_m to x_m+1). In the code we replaced #solution 1 by the following
# solution 2 start
return(a[m]*(x - xd[m])**3 + b[m]*(x-xd[m])**2 + c[m]*(x-xd[m]) + d[m])
# solution 2 end
To find the minimum in a domain x_m to x_(m+1) we use the following code: (we use an instance where m=0, so x from 0.25 to 0.5. The initial guess is 0.3)
fmin_slsqp(phi, x0 = 0.3, bounds=([(0.25,0.5)]), args=(xdata, ydata, 0))
What I would then do (I know it's crude), is iterate this with a for loop to find the minimum on all subdomains and then take the overall minimum. However, the function fmin_slsqp constantly returns the initial guess as the minimum. So there is something wrong, which I do not know how to fix. If you could help me this would be greatly appreciated. Thanks for reading this far.
When I plot your function phi and the data you feed in, I see that its range is of the order of 1e-12. However, fmin_slsqp is unable to handle that level of precision and fails to find any change in your objective.
The solution I propose is scaling the return of your objective by the same order of precision like so:
return(s*1e12)
Then you get good results.
>>> sol = fmin_slsqp(phi, x0=0.3, bounds=([(0.25, 0.5)]), args=(xdata, ydata))
>>> print(sol)
Optimization terminated successfully. (Exit mode 0)
Current function value: 1.0
Iterations: 2
Function evaluations: 6
Gradient evaluations: 2
[ 0.25]
I have a geometric progression like series:
S = x1 + x2 + ..... xn (mod m)
where xi = (x(i-1))*r (mod m) for i>1 and x1=1 , 2<=m<10^9, 1<=r<m, 1<=S<m, 1<=n<p
here m is a prime number and r,m,S are known.
Property of r : If we form a set of r (mod m), r^2 (mod m), ..., r^(m-1) (mod m) then it will contain all the numbers form 1 to m-1.
I want to find the the value of n (if possible). I cannot apply the Geometric Progression (GP) formula here so I made an alternate algorithm making an assumption that these powers will make a cycle of length much smaller than n-1. I thought to find a pattern such that the series repeats itself but this pattern of cycle occurs only for some r's so I failed to do so. Of course, naive approach of setting a loop till m wont work because it's too large and hence took a large amount of time before terminating.
I found a similar problem here.
But in this link there is no property on r to make the algorithm faster. I applied all the answers given here to my code but none is reducing its complexity as required.
I know that somehow I have to use property of r to make an efficient algorithm but I don't know how.
So is there any other pattern we can find out or any use of this property we can make to get the most efficient algorithm? (Basically I don't want to iterate over m.) So please give me an idea of an efficient algorithm to find the n.
I believe I have found a solution. Note that r is a primitive root modulo m by the property of r given.
Consider the geometric sum S = 1 + r + r^2 + ... + r^n. Then we write S in the closed form as S = (r^n - 1) / (r - 1).
Well, we want to solve this equation modulo m for n as we are already given S and r. So we need to solve:
(r^n - 1) / (r - 1) = S (mod m)
=> r^n - 1 = S * (r - 1) (mod m)
=> r^n = S * (r - 1) + 1 (mod m)
We have now run into the Discrete Logarithm Problem.
Using the Baby-step Giant-step algorithm, we can solve this in O(sqrt(m)) which is doable if m is at most 10^9. Below is my implementation in Python 3 where answer(r, m, S) gives the desired answer:
from math import sqrt, ceil
def invmod(r, p):
"""
solves x = r^(-1) modulo p
Note: p must be prime
"""
return pow(r, p-2, p)
def discrete_log(a, r, p):
"""
solves r^x = a (mod m) for x
using the baby-step giant-step algorithm:
https://math.berkeley.edu/~sagrawal/su14_math55/notes_shank.pdf
Note: r must be a primitive root modulo p
"""
m = int(ceil(sqrt(p)))
# compute 1, r, r^2, ..., r^(m-1) modulo p
pows = {pow(r, mp, p): mp for mp in range(m)}
# compute r^(-m) modulo p
y = pow(invmod(r, p), m, p)
# compute a, ay, ay^2, ..., until we find a number
# already in pows
for q in range(m):
z = (a * pow(y, q, p)) % p
if z in pows:
return pows[z] + (q * m)
raise Exception("discrete logarithm not found")
def answer(r, p, S):
"""
if S = 1 + r + r^2 + ... + r^n (mod p),
then answer(r, p, S) = n
"""
a = (S * (r-1) + 1) % p
return discrete_log(a , r, p)