I am trying to solve the following system of linear equations:
#x0 + 1/10 * (x1 + x2 + x3 + x4) = 10
#x1 + 1/15 * (x1 + x2 + x3 + x4 + x5) = 20
#x2 + 1/21 * (x1 + x2 + x3 + x4 + x5 + x6) = 30
To do so I am doing:
a = np.array([[1,1/10,1/10,1/10,1/10,0,0],[0,1+1/15,1/15,1/15,1/15,1/15,0],[0,1/21,1+1/21,1/21,1/21,1/21]])
b=np.array([10,20,30])
x = np.linalg.solve(a, b)
For which I get the following error:
LinAlgError: 1-dimensional array given. Array must be at least two-dimensional
Can someone point out what am I doing wrong? The array has correct entries as I checked. I am following the example here
It looks to me as though there is an error in the last line of the matrix - I count 5 commas rather than 6.
With your version a.shape is (3,)
a = np.array([[1,1/10,1/10,1/10,1/10,0,0],[0,1+1/15,1/15,1/15,1/15,1/15,0],[0,1/21,1+1/21,1/21,1/21,1/21,1/21]])
With the missing element as above, a.shape is (3,7) which seems correct.
Also as noted in the comment, you have 7 unknowns and only 3 equations so you have an underdetermined system.
Related
I wanted to write this expression, in code:
x1 + x2 + x3 + x4 + x5
I can currently do this via:
import sympy as sp
x1, x2, x3, x4, x5 = sp.symbols('x1 x2 x3 x4 x5')
x1 + x2 + x3 + x4 + x5
But unfortunately, this doesn't scale very well, incase I wanted to go from x1 to say, x10,000
Any help would be sincerely appreciated.
I tried using SymPy's summation function, like this:
summation(x(i), (i, 0, n))
But unfortunately got a TypeError, stating:
'Symbol' object is not callable
You can use a generic IndexedBase symbol with a summation:
>>> i = Symbol('i'); x = IndexedBase('x')
>>> Sum(x[i],(i,1,10))
Sum(x[i], (i, 1, 10))
>>> _.doit()
x[10] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + x[7] + x[8] + x[9]
I am trying to find a common tangent to two curves using python but I am not able to solve it.
The equations to the two curves are complicated that involve logarithms.
Is there a way in python to compute the x coordinates of a tangent that is common to both the curves in general. If I have 2 curves f(x) and g(x), I want to find the x-coordinates x1 and x2 on a common tangent where x1 lies on f(x) and x2 on g(x). I am trying f'(x1) = g'(x2) and f'(x1) = f(x1) - f(x2) / (x1 - x2) to get x1 and x2 but I am not able to get values using nonlinsolve as the equations are too complicated.
I want to just find x-coordinates of the common tangent
Can anyone suggest a better way?
import numpy as np
import sympy
from sympy import *
from matplotlib import pyplot as plt
x = symbols('x')
a, b, c, d, e, f = -99322.50019502985, -86864.87072433547, -96876.05627516498, -89703.35055202093, -3390.863799999999, -20942.518
def func(x):
y1_1 = a - a*x + b*x
y1_2 = c - c*x + d*x
c1 = (1 - x) ** (1 - x)
c2 = (x ** x)
y2 = 12471 * (sympy.log((c1*c2)))
y3 = 2*f*x**3 - x**2*(e + 3*f) + x*(e + f)
eqn1 = y1_1 + y2 + y3
eqn2 = y1_2 + y2 + y3
return eqn1, eqn2
val = np.linspace(0, 1)
f1 = sympy.lambdify(x, func(x)[0])(val)
f2 = sympy.lambdify(x, func(x)[1])(val)
plt.plot(val, f1)
plt.plot(val, f2)
plt.show()
I am trying this
x1, x2 = sympy.symbols('x1 x2')
fun1 = func(x1)[0]
fun2 = func(x2)[0]
diff1 = diff(fun1,x1)
diff2 = diff(fun2,x2)
eq1 = diff1 - diff2
eq2 = diff1 - ((fun1 - fun2) / (x1 - x2))
sol = nonlinsolve([eq1, eq2], [x1, x2])
the first thing that needs to be done is to reduce the formulas
for example the first formula is actually this:
formula = x*(1 - x)*(17551.6542 - 41885.036*x) + x*(1 - x)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298
formula = (x-x^2)*(17551.6542 - 41885.036*x) + (x-x^2)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298
# constants
a = 41885.036
b = 17551.6542
c = 24333.3818
d = 12457.6294706944
e = 99322.5001950298
f = 12000
formula = (x-x^2)*(b - a*x) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = (ax^3 -bx^2 + bx - ax^2) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = ax^3 -bx^2 + bx - ax^2 -ax^3 + ax^2 + cx^2 -cx + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
# collect x terms by power (note how the x^3 tern drops out, so its easier).
formula = (c-b)*x^2 + (b-c+d)*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
which is much cleaner and is a quadratic with a log term.
i expect that you can do some work on the log term too, but this is an excercise for the original poster.
likewise the second formula can be reduced in the same way, which is again an excercise for the original poster.
From this, both equations need to be differentiated with respect to x to find the tangent. Then set both formulas to be equal to each other (for a common tangent).
This would completely solve the question.
I actually wonder if this is a python question at all or actually a pure maths question.....
The important point to note is that, since the derivatives are monotonic, for any value of derivative of fun1, there is a solution for fun2. This can be easily seen if you plot both derivatives.
Thus, we want a function that, given an x1, returns an x2 that matches it. I'll use numerical solution because the system is too cumbersome for numerical solution.
import scipy.optimize
def find_equal_value(f1, f2, x, x1):
goal = f1.subs(x, x1)
to_solve = sympy.lambdify(x, (f2 - goal)**2) # Quadratic functions tend to be better behaved, and the result is the same
sol = scipy.optimize.fmin(func=to_solve, x0=x1, ftol=1e-8, disp=False) # The value for f1 is a good starting guess
return sol[0]
I used fmin as the solver above because it worked and I knew how to use it by heart. Maybe root_scalar can give better results.
Using the function above, let's get some pairs (x1, x2) where the derivatives are equal:
df1 = sympy.diff(func(x)[0])
df2 = sympy.diff(func(x)[1])
x1 = 0.25236537 # Close to the zero derivative
x2 = find_equal_value(df1, df2, x, x1)
print(f'Derivative of f1 in x1: {df1.subs(x, x1)}')
print(f'Derivative of f2 in x2: {df2.subs(x, x2)}')
print(f'Error: {df1.subs(x, x1) - df2.subs(x, x2)}')
This results is:
Derivative of f1 in x1: 0.0000768765858083498
Derivative of f2 in x2: 0.0000681969431752805
Error: 0.00000867964263306931
If you want a x2 for several x1s (beware that in some cases the solver hits a value where the logs are invalid. Always check your result for validity):
x1s = np.linspace(0.2, 0.8, 50)
x2s = [find_equal_value(df1, df2, x, x1) for x1 in x1s]
plt.plot(x1s, x2s); plt.grid(); plt.show()
I was trying to verify the mean distance between 2 points in various 3-D and 2-D structures by taking average of multiple random cases. Almost all the time, I was getting a pretty good accuracy except for the case of points on the surface of a sphere. My code uses Gaussian distribution inspired from this answer (see the second most up voted answer)
Here is the python code:
import math as m
from random import uniform as u
sum = 0
for i in range(10000):
x1 = u(-1, 1)
y1 = u(-1, 1)
x2 = u(-1, 1)
y2 = u(-1, 1)
z1 = u(-1, 1)
z2 = u(-1, 1)
if x1 == y1 == z1 == 0:
sum += m.sqrt((x2) ** 2 + (y2) ** 2 + (z2) ** 2)
elif x2 == y2 == z2 == 0:
sum += m.sqrt((x1) ** 2 + (y1) ** 2 + (z1) ** 2)
else:
x1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
y1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
z1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
x2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
y2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
z2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
sum += m.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1-z2) ** 2)
print(sum/10000)
The expected value is 4/3 which is shown here
Arguably the absolute difference is not very large. But the percentage deviation from expected value is around 1% on any run. On the other hand, in all other similar programs with other shapes and same number of random cases, the % deviation is around 0.05% on average.
Also, the value that the code returns is always less than 4/3. This is my major concern.
My guess is that I have implemented the algorithm in a wrong way. Any help is appreciated.
Edit:
After realizing the mistake made in the previous method, I now, first use rejection sampling to get the points lying inside the sphere. This will ensure that after dividing the point vectors with their norms, the resulting unit vector distribution will be uniform. In spite of doing that, I am getting a different result, which is unexpectedly more deviated from expected than the previous one.
To be more precise, the limit approaches 1.25 with this algorithm.
Here is the code:
sum2 = 0
size = 0
for t in range(10000): # Attempt 2
x1 = u(-1, 1)
y1 = u(-1, 1)
x2 = u(-1, 1)
y2 = u(-1, 1)
z1 = u(-1, 1)
z2 = u(-1, 1)
if (x1**2 + y1**2 + z1**2)>1 or (x2**2 + y2**2 + z2**2)>1 or x1==y1==z1==0 or x2==y2==z2==0: continue
size += 1
x1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
y1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
z1 /= m.sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
x2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
y2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
z2 /= m.sqrt(x2 ** 2 + y2 ** 2 + z2 ** 2)
sum2 += m.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2)
print(size)
print(sum2/size)
The initial random values for the two points are contained within a cube, rather than a sphere. After scaling each vector by 1/length, the vectors are on the unit sphere, but they are not evenly distributed across the surface of the sphere.
You will tend to get more vectors near the corners of the cube, compared to the centre of each face. Since the vectors tend to cluster in regions, the average value of the distance between them is less than 4/3.
This will do the trick:
https://mathworld.wolfram.com/SpherePointPicking.html
This code works for me:
from math import sqrt
from random import uniform
sum2 = 0
size = 0
while size < 100000:
x1 = uniform(-1, 1)
y1 = uniform(-1, 1)
x2 = uniform(-1, 1)
y2 = uniform(-1, 1)
z1 = uniform(-1, 1)
z2 = uniform(-1, 1)
r1 = sqrt(x1**2 + y1**2 + z1**2)
r2 = sqrt(x2**2 + y2**2 + z2**2)
if r1 > 1 or r2 > 1 or x1==y1==z1==0 or x2==y2==z2==0: continue
size += 1
x1 /= r1
y1 /= r1
z1 /= r1
x2 /= r2
y2 /= r2
z2 /= r2
sum2 += sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2)
print(sum2/size)
Output was:
1.3337880809331075
As explained the random sampling of this small MC simulation is not done in the proper way.
You want to extract random point uniformly distributed on the surface of the sphere. The easyest way to do so is to use polar coordinates and the choose randomly the angle theta (in 0-pi) and phi (in 0-2pi).
If you want to mantain the cartesian coordinates you have to transform your distribution using the known transformation matrix from cartesian to 3-d polar coordinate system.
I am trying to find the gradient of the function
f(x) = w1 * x1^2 + w2 * x2
where x is a vector coordinate (x1,x2).
def gradient(w1, w2, x):
x= (x1,x2)
gradx1=2*w1*x1 + w2 * x2
gradx2= w2 + w1 * x1^2
return (gradx1, gradx2)
My code is coming up with a nameError, saying x1 is not defined when calling the function:
gradient(5, 6, (10,10))
First things first:
x1, x2 = x # unpack your coord tuple
And secondly:
gradx2= w2 + w1 * x1 ** 2 # or gradx2= w2 + w1 * x1 * x1
in python ^ is bitwise XOR. Exponentiation is **.
x is a tuple which you need to unpack like so:
x1, x2 = x
Rather than:
x = (x1, x2)
I want to solve a system of 6 nonlinear equations using Python. I found that I can use scipy's fsolve pretty easily to solve a system of 3 nonlinear equations. However, when I expand this to a larger system, I find that the solution does not solve the system of equations. Is there something I can correct that will allow for the solution of 6 nonlinear equations?
import numpy as np
from scipy.optimize import fsolve
def system(z):
#arbitrary system of 3 nonlinear equations
x1 = z[0]
x2 = z[1]
x3 = z[2]
F = np.empty((3))
F[0] = 20* x1 + x2**2
F[1] = x2 - x1
F[2] = x3 + 5 - x1*x2
return F
def system2(z):
#arbitrary system of 6 nonlinear equations
x1 = z[0]
x2 = z[1]
x3 = z[2]
x4 = z[3]
x5 = z[4]
x6 = z[5]
F = np.empty((6))
F[0] = 20* x1 + x2**2
F[1] = x2 - x1
F[2] = x3 + 5 - x1*x2
F[3] = x3 + x2
F[4] = x5 + x4**2
F[5] = x6**2 + x1 - 20
return F
uInitial = np.array([1,1,1])
u = fsolve(system,uInitial)
print('Solution: ',u)
print('Solution check: ',system(u),'\n') #yields zeros as expected
vInitial = np.array([1,1,1,1,1,1])
v = fsolve(system2,vInitial)
print('Solution: ',v)
print('Solution check: ',system2(v)) #unexpectedly does not yield zeros. Equations not solved correctly.
When applying the given solution back into the system of equations, I should expect to receive zeros (or nearly zero). This would confirm that the computed solution solves the given set of equations. I tried checking with this method for both the system of 3 equations and the system of 6 equations, but only the system of 3 equations is solved correctly with this check. What can I do to solve the system of 6 nonlinear equations?
Your system is inconsistent and your initial guess is off. Try adding fourth equation to the first system of three equations:
F[0] = 20 * x1 + x2**2 # "first" equation
F[1] = x2 - x1 # "second" (=> x1 == x2)
F[2] = x3 + 5 - x1*x2 # "third"
F[3] = x3 + x2 # "fourth" equation (=> x3 == -x2)
First, let's solve first three equations. From the second equation it follows that x1 is equal to x2. Therefore the first equation can be re-written as:
F[0] = 20 * x1 + x1**2
which leads to x1 = -20 (and x2 = -20). Using this in the third equation leads to x3 = 395. Try to modify initial conditions for the first system to uInitial = np.array([-30, -30, 1]) - you should get the correct answer.
Now, let's solve all four equations. The third equation, using the fact that x2 == x1, can be re-written as:
F[2] = x3 + 5 - x1**2
From the fourth equation it follows that x3 == -x2 (and so x3 == -x1 as well). Therefore, this equation can be rewritten as x3 + 5 - x3**2 == 0 => x3 = 0.5 +(-) sqrt(21)/2 which is different from 395 that we got above using first three equations.
This shows that you have an inconsistent system of equations which has no solution.