I am trying to write Python code that will return a Jacobian matrix. After installing numdifftools and running the in-built function numdifftools.Jacobian() I get this:
numdifftools.core.Jacobian object at 0x1032fe2d0
All examples I find online return this result for me. Is there a command I'm missing or am I miss-interpreting how this function works??
# To approximate a solution for a series of
# overdeterministic, non-linear equations.
# Find the point of intersection
import scipy
import numpy as np
import numdifftools as nd
# The matrix A, equations stored in rows in the form:
# [x^2, y^2, x, y]
def MatrixA():
return np.matrix([ [1, 1, 0, 0],
[1, 1, 4, -2],
[0, 0, 4, -2],
[4, 0, 22, -9],
[5, 0, 0, 1]
])
# The matrix B, the answers of the equations in Matrix A
def MatrixB():
return np.matrix([ [16],
[6],
[-13],
[31.5204],
[1.288]
])
#Using the Moore-Penrose method to solve
#an overdetermined set of equations
def MoorePenrose(A):
Ans = A.getT() * A
Ans = Ans.getI()
Ans = Ans * A.getT()
return Ans
# Linearise the equations by using the Newton method
# This will generate the best possible linear version
# of the nonlinear system.
def Linearise(A):
return nd.Jacobian(A)
#=============================================
# Program Main() {
#=============================================
#Read in A matrix of equations
A = MatrixA()
#Read in B matrix of solutions (RHS of A Matrices equations)
B = MatrixB()
#Solution =>
#Linearise Matrix A
A = Linearise(A)
print A
#A = Moorse Penrose psuedoinverse of A
A = MoorePenrose(A)
#Unknowns Matrix X = A * B
A = A * B
# Print out the unknowns Matrix.
print A
#=============================================
# } Main End;
#=============================================
Investigating the same question for multiple output function of multiple variables, I made this simple example demonstrating the use of numdifftools Jacobian function.
Please note the use of numpy array to define function multiple outputs and not lists.
import numpy as np
import numdifftools as nd
# Define your function
# Can be R^n -> R^n as long as you use numpy arrays as output
def f(x):
return np.array([x[0],x[1]])
# Define your Jacobian function
f_jacob = nd.Jacobian(f)
# Use your Jacobian function at any point you want.
# In our case, for a R² -> R² function, it returns a 2x2 matrix with all partial derivatives of all outputs wrt all inputs
print(f_jacob([1,2]))
Execution returns
[[1. 0.]
[0. 1.]]
Related
Scipy's pdist function expects an evenly shaped numpy array as input.
Working example:
from scipy.spatial.distance import pdist
from scipy.spatial.distance import squareform
#Example distance function.
def dfun(u, v):
return u.sum() + v.sum()
dat0 = np.array([-1, 1,-3, 1])
dat1 = np.array([-1, 1,-3, 1])
dat2 = np.array([ 1, 1, 1, 1])
data = np.array([dat0, dat1, dat2])
distance_matrix = pdist(data, dfun)
squareform(distance_matrix)
I got a custom distance function which works with run-length encoded data, thus the arrays may vary in size. When using the following input
dat0 = np.array([-1, 1,-4, 1])
dat1 = np.array([-1, 1,-3, 1, 1])
dat2 = np.array([ 1,-6])
A value error ValueError: A 2-dimensional array must be passed. is raised even though the distance function would be just fine handling the input. Does there exist an alternative to calculate these values?
Edit: the distance function in the above snippet is just an example for a metric which does not care about the actual number of elements inside the datapoint. In my case https://github.com/mclmza/AWarp is used which computes the dtw for sparse data sets example series: [1,-456,1,1,-23,1], thus padding the data is not a valid option.
If I understand correctly, you want to compute the distances using awarp, but that distance function takes signals of varying length. So you need to avoid creating an array, because NumPy doesn't allow 'ragged' arrays. Then I think you can do this:
from itertools import combinations
from scipy.spatial.distance import squareform
# Example distance function.
def dfun(u, v):
return u.sum() + v.sum()
dat0 = np.array([-1, 1,-4, 1])
dat1 = np.array([-1, 1,-3, 1, 1])
dat2 = np.array([ 1,-6])
data = [dat0, dat1, dat2]
dists = [dfun(a, b) for a, b in combinations(data, r=2)]
squareform(dists)
For your example, this yields:
array([[ 0, -4, -8],
[-4, 0, -6],
[-8, -6, 0]])
And if dfun = awarp then you get this output for those signals:
array([[ 0. , 0. , 2.23606798],
[ 0. , 0. , 2.44948974],
[ 2.23606798, 2.44948974, 0. ]])
I guess this approach only works if dfun is commutative, which I think awarp is.
I am using quad from scipy.integrate to get an integral in a limited range from an object. suppose the target object is in the blow:
∫expm(A*X).expm(B*X)dx
which both A and B are numpy matrix.
To solve this I have used blow code:
from scipy.integrate import quad
from scipy.linalg import expm
import numpy as np
def integrand(X, A, B):
return np.dot(expm(A*X),expm(B*X))
A = np.array([[1, 2], [3, 4]])
B = np.array([[1, 2], [3, 4]])
I= quad(integrand, 0, 1, args=(A,B))
But for the result I get this error:
TypeError: only length-1 arrays can be converted to Python scalars
I know that The error "only length-1 arrays can be converted to Python scalars" is raised when the function expects a single value but you pass an array instead. but my problem is based on array. so how can I fix it.
As pointed in the comments, quad expects a scalar function. You can always pass the function to a scalar by adding the index as an output:
def integrand(X, A, B, ix=None):
""" pass ix=None to return the matrix, ix = 0,1,2,3 to return an element"""
output = np.dot(expm(A*X),expm(B*X))
if ix is None:
return output
i, j = ix//2, ix%2
return output[i,j]
I= np.array([quad(integrand, 0, 1, args=(A,B, i))[0]
for i in range(4)]).reshape(2,2)
I
>>array([[1031.61668602, 1502.47836021],
[2253.71754031, 3285.33422634]])
Note that this is very inefficient since you are calculating the integral 4 times, as long as this doesn't bother you.
Alternatively, use trapz:
x_i = np.linspace(0,1,60)
np.trapz([integrand(x, A, B) for x in x_i], x=x_i, axis=0)
>>array([[1034.46472361, 1506.62915374],
[2259.94373062, 3294.40845422]])
quadpy does vectorized computation. The fact that expm only works on square matrices (and not on lists of square matrices) requires a bit of juggling with the matrix shapes, though.
from quadpy import quad
import numpy as np
from scipy.linalg import expm
A = np.array([[1, 2], [3, 4]])
B = np.array([[1, 2], [3, 4]])
def integrand(X):
expAX = np.array([expm(A * x) for x in X])
expAX = np.moveaxis(expAX, 0, -1)
#
expBX = np.array([expm(B * x) for x in X])
expBX = np.moveaxis(expBX, 0, -1)
return np.einsum("ij...,jk...->ik...", expAX, expBX)
val, err = quad(integrand, 0, 1)
print(val)
[[1031.61668602 1502.47836021]
[2253.71754031 3285.33422633]]
I am trying to formulate an optimization problem in the following way:
My optimization variable x is a n*n matrix.
x should be PSD.
It should be in the range 0<=x<=I. Meaning, it would be in the range from the all zeros square matrix to n dimensional identity matrix.
Here is what I have come up with so far:
import cvxpy as cp
import numpy as np
import cvxopt
x = cp.Variable((2, 2), PSD=True)
a = cvxopt.matrix([[1, 0], [0, 0]])
b = cvxopt.matrix([[.5, .5], [.5, .5]])
identity = cvxopt.matrix([[1, 0], [0, 1]])
zeros = cvxopt.matrix([[0, 0], [0, 0]])
constraints = [x >= zeros, x <= identity]
objective = cp.Maximize(cp.trace(x*a - x * b))
prob = cp.Problem(objective, constraints)
prob.solve()
This gives me a result of [[1, 0], [0, 0]] as the optimal x, with a maximum trace of .5. But that should not be the case. Because I have done this same program in CVX in matlab and I got the answer matrix as [[.85, -.35], [-.35, .14]] with an optimal value of .707. Which is correct.
I think my constraint formulation is not correct or not following cvxpy standards. How do I enforce the constraints in my program correctly?
(Here is my matlab version of the code:)
a = [1, 0; 0, 0];
b = [.5, .5; .5, .5];
cvx_begin sdp
variable x(2, 2) hermitian;
maximize(trace(x*a - x*b))
subject to
x >= 0;
x <= eye(2);
cvx_end
TIA
You need to use the PSD constraint. If you compare a matrix against a scalar, cvxpy does elementwise inequalities unless you use >> or <<. You already have constrained x to be PSD when you created it so all you need to change is:
constraints = [x << np.eye(2)]
Then I get your solution:
array([[ 0.85355339, -0.35355339],
[-0.35355339, 0.14644661]])
I'm trying to get all eigenvalues from a 3x3 matrix by using Power Method in Python. However my method returns diffrent eigenvalues from the correct ones for some reason.
My matrix: A = [[1, 2, 3], [2, 4, 5], [3, 5,-1]]
Correct eigenvalues: [ 8.54851285, -4.57408723, 0.02557437 ]
Eigenvalues returned by my method: [ 8.5485128481521926, 4.5740872291939381, 9.148174458392436 ]
So the first one is correct, second one has wrong sign and the third one is all wrong. I don't know what I'm doing wrong and I can't see where have I made mistake.
Here's my code:
import numpy as np
import numpy.linalg as la
eps = 1e-8 # Precision of eigenvalue
def trans(v): # translates vector (v^T)
v_1 = np.copy(v)
return v_1.reshape((-1, 1))
def power(A):
eig = []
Ac = np.copy(A)
lamb = 0
for i in range(3):
x = np.array([1, 1, 1])
while True:
x_1 = Ac.dot(x) # y_n = A*x_(n-1)
x_norm = la.norm(x_1)
x_1 = x_1/x_norm # x_n = y_n/||y_n||
if(abs(lamb - x_norm) <= eps): # If precision is reached, it returns eigenvalue
break
else:
lamb = x_norm
x = x_1
eig.append(lamb)
# Matrix Deflaction: A - Lambda * norm[V]*norm[V]^T
v = x_1/la.norm(x_1)
R = v * trans(v)
R = eig[i]*R
Ac = Ac - R
return eig
def main():
A = np.array([1, 2, 3, 2, 4, 5, 3, 5, -1]).reshape((3, 3))
print(power(A))
if __name__ == '__main__':
main()
PS. Is there a simpler way to get the second and third eigenvalue from power method instead of matrix deflaction?
With
lamb = x_norm
you ever only compute the absolute value of the eigenvalues. Better compute them as
lamb = dot(x,x_1)
where x is assumed to be normalized.
As you do not remove the negative eigenvalue -4.57408723, but effectively add it instead, the largest eigenvalue in the third stage is 2*-4.574.. = -9.148.. where you again computed the absolute value.
I didn't know this method, so I googled it and found here:
http://ergodic.ugr.es/cphys/LECCIONES/FORTRAN/power_method.pdf
that it is valid only for finding the leading (largest) eigenvalue, thus, it seems that it is working for you fine, and it is not guaranteed that the following eigenvalues will be correct.
Btw. numpy.linalg.eig() works faster than your code for this matrix, but I am guessing you implemented it as an exercise.
I've been trying to visualize QR decomposition in a step by step fashion, but I'm not getting expected results. I'm new to numpy so it'd be nice if any expert eye could spot what I might be missing:
import numpy as np
from scipy import linalg
A = np.array([[12, -51, 4],
[6, 167, -68],
[-4, 24, -41]])
#Givens
v = np.array([12, 6])
vnorm = np.linalg.norm(v)
W_12 = np.array([[v[0]/vnorm, v[1]/vnorm, 0],
[-v[1]/vnorm, v[0]/vnorm, 0],
[0, 0, 1]])
W_12 * A #this should return a matrix such that [1,0] = 0
#gram-schmidt
A[:,0]
v = np.linalg.norm(A[:,0]) * np.array([1, 0, 0])
u = (A[:,0] - v)
u = u / np.linalg.norm(u)
W1 = np.eye(3) - 2 * np.outer(u, u.transpose())
W1 * A #this matrix's first column should look like [a, 0, 0]
any help clarifying the fact that this intermediate results don't show the properties that they are supposed to will be greatly received
NumPy is designed to work with homogeneous multi-dimensional arrays, it is not specifically a linear algebra package. So by design, the * operator is element-wise multiplication, not the matrix product.
If you want to get the matrix product, there are a few ways:
You can create np.matrix objects, rather than np.ndarray objects, for which the * operator is the matrix product.
You can also use the # operator, as in W_12 # A, which is the matrix product.
Or you can use np.dot(W_12, A) or W_12.dot(A), which computes the dot product.
Any one of these, using the data you give, returns the following for Givens rotation:
>>> np.dot(W_12 A)[1, 0]
-2.2204460492503131e-16
And this for the Gram-Schmidt step:
>>> (W1.dot(A))[:, 0]
array([ 1.40000000e+01, -4.44089210e-16, 4.44089210e-16])