Factoring a polynomial with respect to specific terms - python

import numpy as np
import sympy as sp
from sympy import *
init_printing()
uVars = list(symbols(', '.join([f'u{n}' for n in range(1, 3 + 1)])))
aVars = list(symbols(', '.join([f'a{n}' for n in range(1, 3 + 1)])))
lambda1, mu = symbols('lambda, mu')
U = np.array([ [0, -uVars[2], uVars[1]], [uVars[2], 0, -uVars[0]], [-uVars[1], uVars[0], 0] ])
a = np.array([ [aVars[0], 0, 0], [0, aVars[1], 0], [0, 0, aVars[2]] ])
I = np.eye(3)
L = a*lambda1 + U
preCharPoly = L - mu*I
preCharPoly_sym = sp.Matrix(preCharPoly)
factor(preCharPoly_sym.det())
The above code outputs the following polynomial:
However, I require the polynomial to be factored with respect to the variables lambda and mu as shown here:
I have been examining the documentation at https://docs.sympy.org/latest/modules/simplify/simplify.html but cannot figure out how to do what is desired. How do I specify factor() or simplify() to perform their tasks with respect to lambda and mu?

Related

linear algebra (partial) solving in python

I have a dictionary with a tuple as key and a result as value.
I'm looking for a way to "solve" as many keys as possible, even if it's not possible to "solve" all of then.
input : {(A, C):1,(A, B, C): 1}
output : {(A, C):1, (A, B, C): 1, B:0}
in other word :
modified input :
1*A + 0*B + 1*C = 1
1*A + 1*B + 1*C = 1
output :
A = ?
B = 0
C = ?
I can only use numpy and scipy.
I tried this, but it must be square matrix :
import numpy as np
a = np.array([[1, 0, 1], [1, 1, 1]])
b = np.array([1, 1])
from scipy import linalg
x = linalg.solve(a, b)
print(x)
Do you have ideas where I should look at ?
this code does the trick, but it's not very 'clean'
import numpy as np
A=np.array([[1, 0, 1], [1, 1, 1]])
B=np.array([1,1])
s = solutionNonSquare = np.linalg.lstsq(A, B)[0]
for i,val in enumerate(s):
if val < 0.0001:
print('x[',i,'] = 0')
else:
print('x[',i,'] = ?')
print(s)
Thanks a lot for your smartness
Matrix a is Non square Matrix, so it does not have full Rank. However, we can compute pseudo inverse, using np.linalg.pinv and then we can compute x = np.matmul(a_psudo_inv, b)
import numpy as np
a = np.array([[1, 0, 1], [1, 1, 1]])
b = np.array([1, 1])
from numpy import linalg
a_psudo_inv = np.linalg.pinv(a)
print(a_psudo_inv)
print(a_psudo_inv.shape)
x = np.matmul(a_psudo_inv, b)
print(x)
Solution >> [5.00000000e-01 5.55111512e-16 5.00000000e-01]

Using LinearOperator as nonlinear constraints in Scipy optimize

I'm trying to use the optimization module in SciPy to solve constrained optimization problem. I need to implement the 'hess' argument. In scipy's documentation and tutorial, their hessian are simply [[2, 0], [0, 0]] and [[2, 0], [0, 0]]. However, my hessian is something like [[(-24)*x[0]**2 + 48*x[0]-16, 0], [0, 0]] and [[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]] so that I cannot simply use numpy.array to do multiplication. It seems that I should send a LinearOperator object to the 'hess' arguement. Examples of using LinearOperator is unclear in both scipy.optimize tutorial and LinearOperator documentation since they only show examples of lower dimension. I'm wondering how to correctly use it?
The problem formulation is
my code is:
import numpy as np
from scipy.optimize import Bounds
from scipy.optimize import NonlinearConstraint
from scipy.optimize import minimize
def f(x):
return (-x[0]-x[1])
def grad(x):
return np.array([-1, -1])
def hess(x):
return np.array([[0, 0], [0, 0]])
def cons_f(x):
return [(-2)*x[0]**4 + 8*x[0]**3 + (-8)*x[0]**2 + x[1] -2, (-4)*x[0]**4 + 32*x[0]**3 + (-88)*x[0]**2 + 96*x[0] + x[1] -36]
def cons_Jacobian(x):
return [[(-8)*x[0]**3 + 24*x[0]**2 - 16*x[0], 1], [(-16)*x[0]**3 + 96*x[0]**2 - 176*x[0] +96, 1]]
def cons_Hessian(x,v):
# TODO
return v[0]*[[(-24)*x[0]**2 + 48*x[0]-16, 0], [0, 0]] + v[1]*[[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]]
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 0, jac=cons_Jacobian, hess=cons_Hessian)
bounds = Bounds([0, 0], [3.0, 4.0])
x0 = np.array([0.5, 1])
res = minimize(f, x0, method='trust-constr', jac=grad, hess=hess,
constraints=[nonlinear_constraint],bounds=bounds)
The cons_Hessian(x,v)is absolutely wrong in my code.
In their example, although hessians are simply[[2, 0], [0, 0]] and [[2, 0], [0, 0]], the usage is confusing. I don't understand where p comes in.
from scipy.sparse.linalg import LinearOperator
def cons_H_linear_operator(x, v):
def matvec(p):
return np.array([p[0]*2*(v[0]+v[1]), 0])
return LinearOperator((2, 2), matvec=matvec)
nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
jac=cons_J, hess=cons_H_linear_operator)
There's no need to use a LinearOperator. You only need to ensure that cons_f, cons_Jacobian and cons_Hessian return np.ndarrays. That's the reason why you can't evaluate your cons_Hessian. Additionally, it's highly recommended to use double literals instead of integers, i.e. -2.0 instead of 2 to prevent that the function returns np.ndarrays with a integer dtype.
Your example works for me by writing these functions as follows:
def cons_f(x):
con1 = (-2.0)*x[0]**4 + 8*x[0]**3 + (-8)*x[0]**2 + x[1] - 2
con2 = (-4)*x[0]**4 + 32*x[0]**3 + (-88)*x[0]**2 + 96*x[0] + x[1] -36
return np.array([con1, con2])
def cons_Jacobian(x):
con1_grad = [(-8.0)*x[0]**3 + 24*x[0]**2 - 16*x[0], 1]
con2_grad = [(-16)*x[0]**3 + 96*x[0]**2 - 176*x[0] +96, 1]
return np.array([con1_grad, con2_grad])
def cons_Hessian(x,v):
con1_hess = np.array([[(-24.0)*x[0]**2 + 48*x[0]-16, 0], [0, 0]])
con2_hess = np.array([[(-48)*x[0]**2 + 192*x[0]-176, 0], [0, 0]])
return v[0]*con1_hess + v[1]*con2_hess

Python linprog minimization--simplex method

I'm using scipy.optimize.linprog library to calculate the minimization using the simplex method. I'm working on this problem in my textbook and I'm hoping someone can point me in the right direction because I'm not getting the output I expect. The problem is:
Minimize w = 10*y1 + 15*y2 + 25*y3
Subject to: y1 + y2 + y3 >= 1000
y1 - 2*y2 >= 0
y3 >= 340
with y1 >= 0, y2 >= 0
The code I wrote for this is:
import numpy as np
import pandas as pd
from scipy.optimize import linprog
A = np.array([
[1, 1, 1],
[1,-2, 0],
[0, 0, 1]])
b = np.array([1000,0,340])
c = np.array([-10,-15,-25])
res = linprog(c, A_ub=A, b_ub=b,
bounds=(0, None))
print('Optimal value:', res.fun, '\nX:', res.x)
Which gives the output:
Optimal value: -18400.0
X: [ 0. 660. 340.]
I expect it to be:
Optimal value: -15100.0
X: [ 660. 0. 340.]
I can't seem to find consistency with this function but maybe it's the way I'm using it.
You've set up the inputs slightly wrong; see the manual. Specifically, you have a number of sign errors.
Your vector c has the wrong sign; linprog minimizes c x so c should just be the coefficients in w = c x
Your vector b and matrix A have the wrong sign. Their signs should be inverted to switch from your form of constraint f(x) >= const to the desired form for the linprog method, which is a less-than-or-equal, i.e. -f(x) <= - const
You are missing the final two constraints.
Your proposed minimum is < 0, which is obviously impossible as
w = 10*x1 + 15*x2 + 25*x3 is always positive with your constraints as x1,x2,x3>=0.
The correct code reads:
import numpy as np
from scipy.optimize import linprog
A = np.array([[-1, -1, -1], [-1,2, 0], [0, 0, -1], [-1, 0, 0], [0, -1, 0]])
b = np.array([-1000, 0, -340, 0, 0])
c = np.array([10,15,25])
res = linprog(c, A_ub=A, b_ub=b,bounds=(0, None))
print('Optimal value:', res.fun, '\nX:', res.x)
# python2
# ('Optimal value:', 15100.0, '\nX:', array([ 660., 0., 340.]))
# python3
# Optimal value: 15099.999961403426
# X: [6.59999996e+02 1.00009440e-07 3.40000000e+02]
As the positiveness of y1 and y2 can be guaranteed under bounds=(0, None), a simplified version of code is shown as below:
import numpy as np
from scipy.optimize import linprog
A = np.array([[-1, -1, -1], [-1,2, 0], [0, 0, -1]])
b = np.array([-1000, 0, -340])
c = np.array([10,15,25])
res = linprog(c, A_ub=A, b_ub=b,bounds=(0, None))
print('Optimal value:', res.fun, '\nX:', res.x)
Output:
Optimal value: 15099.999961403195
X: [6.59999996e+02 1.00009440e-07 3.40000000e+02]

Minimize objective function using limfit.minimize in Python

I am having a problem with package lmfit.minimize minimization procedure. Actually, I could not create a correct objective function for my problem.
Problem definition
My function: yn = a_11*x1**2 + a_12*x2**2 + ... + a_m*xn**2,where xn- unknowns, a_m -
coefficients. n = 1..N, m = 1..M
In my case, N=5 for x1,..,x5 and M=3 for y1, y2, y3.
I need to find the optimum: x1, x2,...,x5 so that it can satisfy the y
My question:
Error: ValueError: operands could not be broadcast together with shapes (3,) (3,5).
Did I create the objective function of my problem properly in Python?
My code:
import numpy as np
from lmfit import Parameters, minimize
def func(x,a):
return np.dot(a, x**2)
def residual(pars, a, y):
vals = pars.valuesdict()
x = vals['x']
model = func(x,a)
return y - model
def main():
# simple one: a(M,N) = a(3,5)
a = np.array([ [ 0, 0, 1, 1, 1 ],
[ 1, 0, 1, 0, 1 ],
[ 0, 1, 0, 1, 0 ] ])
# true values of x
x_true = np.array([10, 13, 5, 8, 40])
# data without noise
y = func(x_true,a)
#************************************
# Apriori x0
x0 = np.array([2, 3, 1, 4, 20])
fit_params = Parameters()
fit_params.add('x', value=x0)
out = minimize(residual, fit_params, args=(a, y))
print out
if __name__ == '__main__':
main()
Directly using scipy.optimize.minimize() the code below solves this problem. Note that with more points yn you will tend to get the same result as x_true, otherwise more than one solution exists. You can minimize the effect of the ill-constrained optimization by adding boundaries (see the bounds parameter used below).
import numpy as np
from scipy.optimize import minimize
def residual(x, a, y):
s = ((y - a.dot(x**2))**2).sum()
return s
def main():
M = 3
N = 5
a = np.random.random((M, N))
x_true = np.array([10, 13, 5, 8, 40])
y = a.dot(x_true**2)
x0 = np.array([2, 3, 1, 4, 20])
bounds = [[0, None] for x in x0]
out = minimize(residual, x0=x0, args=(a, y), method='L-BFGS-B', bounds=bounds)
print(out.x)
If M>=N you could also use scipy.optimize.leastsq for this task:
import numpy as np
from scipy.optimize import leastsq
def residual(x, a, y):
return y - a.dot(x**2)
def main():
M = 5
N = 5
a = np.random.random((M, N))
x_true = np.array([10, 13, 5, 8, 40])
y = a.dot(x_true**2)
x0 = np.array([2, 3, 1, 4, 20])
out = leastsq(residual, x0=x0, args=(a, y))
print(out[0])

Weighted sum of adjacent values in numpy array

What is the easiest/fastest way to take a weighted sum of values in a numpy array?
Example: Solving the heat equation with the Euler method
length_l=10
time_l=10
u=zeros((length_l,length_l))# (x,y)
u[:, 0]=1
u[:,-1]=1
print(u)
def dStep(ALPHA=0.1):
for position,value in ndenumerate(u):
D2u= (u[position+(1,0)]-2*value+u[position+(-1, 0)])/(1**2) \
+(u[position+(0,1)]-2*value+u[position+( 0,-1)])/(1**2)
value+=ALPHA*D2u()
while True:
dStep()
print(u)
D2u should be the second central difference in two dimensions. This would work if I could add indexes like (1,4)+(1,3)=(2,7). Unfortunately, python adds them as (1,4)+(1,3)=(1,4,1,3).
Note that computing D2u is equivalent to taking a dot product with this kernel centered around the current position:
0, 1, 0
1,-4, 1
0, 1, 0
Can this be vectorised as a dot product?
I think you want something like:
import numpy as np
from scipy.ndimage import convolve
length_l = 10
time_l = 10
u = np.zeros((length_l, length_l))# (x,y)
u[:, 0] = 1
u[:, -1] = 1
alpha = .1
weights = np.array([[ 0, 1, 0],
[ 1, -4, 1],
[ 0, 1, 0]])
for i in range(5):
u += alpha * convolve(u, weights)
print(u)
You could reduce down a bit by doing:
weights = alpha * weights
weights[1, 1] = weights[1, 1] + 1
for i in range(5):
u = convolve(u, weights)
print(u)

Categories

Resources