Newton method in python for multivariables (system of equations) - python

My code is running fine for first iteration but after that it outputs the following error:
ValueError: matrix must be 2-dimensional
To the best of my knowledge (which is not much in python), my code is correct. but I don't know, why it is not running correctly for all given iterations. Could anyone help me in this problem.
from __future__ import division
import numpy as np
import math
import matplotlib.pylab as plt
import sympy as sp
from numpy.linalg import inv
#initial guesses
x = -2
y = -2.5
i1 = 0
while i1<5:
F= np.matrix([[(x**2)+(x*y**3)-9],[(3*y*x**2)-(y**3)-4]])
theta = np.sum(F)
J = np.matrix([[(2*x)+y**3, 3*x*y**2],[6*x*y, (3*x**2)-(3*y**2)]])
Jinv = inv(J)
xn = np.array([[x],[y]])
xn_1 = xn - (Jinv*F)
x = xn_1[0]
y = xn_1[1]
#~ print theta
print xn
i1 = i1+1

I believe xn_1 is a 2D matrix. Try printing it you and you will see [[something], [something]]
Therefore to get the x and y, you need to use multidimensional indexing. Here is what I did
x = xn_1[0,0]
y = xn_1[1,0]
This works because within the 2D matrix xn_1 are two single element arrays. Therefore we need to further index 0 to get that single element.
Edit: To clarify, xn_1[1,0] means to index 1 and then take that subarray and index 0 on that. And although according to Scipy it may seem that it should be functionally equivalent to xn_1[1][0], that only applies to the general np.array type and not the np.matrix type. Here is an excellent thread on SO that explains this.
So you should use the xn_1[1,0] way to get the element you want.

xn_1 is a numpy matrix, so it's elements are accessed with the item() method, not like an array. (with []s)
So just change
x = xn_1[0]
y = xn_1[1]
to
x = xn_1.item(0)
y = xn_1.item(1)

Related

Python - Scipy Multivariate normal generalized to 1 dimension

When running y = multivariate_normal(np.zeros(d), np.eye(d)).rvs() we obtain a sample of dimension (d, ). However, when d=1 we obtain a scalar, which makes sense since it's 1 dimensional. Unfortunately, I have some piece of code that must work for any number of dimensions, including d=1, and basically takes the dot product of a d dimensional vector x with y. This breaks for d=1. How can I fix it?
import numpy as np
from scipy.stats import multivariate_normal as MVN
def mwe_function(d, x):
"""Minimal Working Example"""
y = MVN(np.zeros(d), np.eye(d)).rvs()
return x # y
mwe_function(2, np.ones(2)) # This works
mwe_function(1, np.ones(1)) # This doesn't
IMPORTANT: I want to avoid if statements. One could simply use scipy.stats.norm in that case, but I want to avoid if statements as they would slow down the code.
You can use np.reshape to fix the shape of your sample. By using -1 to specify the length of the first dimension, you will always get a 1-dimensional array and no scalar.
import numpy as np
from scipy.stats import multivariate_normal as MVN
def mwe_function(d, x):
"""Minimal Working Example"""
y = MVN(np.zeros(d), np.eye(d)).rvs().reshape([-1])
return x # y
v0 = mwe_function(2, np.ones(2)) # This works
print(v0) # -0.5718013906409207
v1 = mwe_function(1, np.ones(1)) # This works as well :-)
print(v1) # -0.20196038784485093
where .reshape([-1]) does the job.
Personally, I prefer reshaping over using np.atleast_1d, since the effect is directly visible - but in the end it is a matter of taste.

Error for a given function: only size-1 arrays can be converted to Python scalars

i am a newbie and currently trying to plot this function so I can choose a range of x values for which I should perform my experiments in the ChemistryLab.
I found different articles on plotting functions and it all worked with generic functions like sin(x).
But once I input my function it does not work. The problem already occurs after the first two lines:
import numpy as np
import math
X = np.linspace(0, 512, 256)
f = ((x+22)- math.sqrt((x+22)**2-4*2*x))
--> TypeError: only size-1 arrays can be converted to Python scalars
I found threads saying X should be vectorize, however I could not come up with a solution.
Thanks for help in advance!
Create a vectorized function. For example:
equation_func = np.vectorize(math.sqrt)
new_f = equation_func(X)
Swap math.sqrt with a function containing your more sophisticated equation and you're home.
A good way to implement a mathematical function in Python is, perhaps unsurprisingly, as a Python function. Then you can, for example, use that function in a list comprehension to get an array of values:
import numpy as np
import math
import matplotlib.pyplot as plt
X = np.linspace(0, 512, 256)
def f(x):
return x + 22 - math.sqrt((x + 22)**2 - 8 * x)
Y = np.array([f(x) for x in X])
plt.plot(X, Y);

Python find closest values of a coordinate array to another effciently

I have two sets of arrays, and what I am looking for is the index of the closest point in array2 to each value in array1, for example:
import numpy as np
from scipy.spatial import distance
array1 = np.array([[1,2,1], [4,2,6]])
array2 = np.array([[0,0,1], [4,5,0], [1,2,0], [6,5,0]])
def f(x):
return distance.cdist([x], array2 ).argmin()
def array_map(x):
return np.array(list(map(f, x)))
array_map(array1)
This code returns the correct results but is slow when both arrays are very big. I was wondering if it was possible to make this any quicker ?
Thanks to #Max7CD here is a working solution that works quite efficiantly (at least for my purpose):
from scipy import spatial
tree =spatial.KDTree(array2)
slitArray = np.split(array1, 2) #I split the data so that the KDtree doesn't take for ever and so that I can moniter progress, probably useless
listFinal = []
for elem in slitArray:
a = tree.query(elem)
listFinal.append(a[1])
print("Fnished")
b = np.array(listFinal).ravel()

SciPy/numpy: Only keep maximum value of a sparse matrix block

I am trying to operate on a large sparse matrix (currently 12000 x 12000).
What I want to do is to set blocks of it to zero but keep the largest value within this block.
I already have a running solution for dense matrices:
import numpy as np
from scipy.sparse import random
np.set_printoptions(precision=2)
#x = random(10,10,density=0.5)
x = np.random.random((10,10))
x = x.T * x
print(x)
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.max(sub)
sub[sub < z] = 0
sizes = np.asarray([0,1,5,4])
sizes_sum = np.cumsum(sizes)
for i in range(1,len(sizes)):
current_i_min = sizes_sum[i-1]
current_i_max = sizes_sum[i]
for j in range(1,len(sizes)):
if i >= j:
continue
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
keep_only_max(current_i_min, current_i_max, current_j_min, current_j_max)
keep_only_max(current_j_min, current_j_max, current_i_min, current_i_max)
print(x)
This, however, doesn't work for sparse matrices (try uncommenting the line on top).
Any ideas how I could efficiently implement this without calling todense()?
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.max(sub)
sub[sub < z] = 0
For a sparse x, the sub slicing works for csr format. It won't be as fast as the equivalent dense slice, but it will create a copy of that part of x.
I'd have to check the sparse max functions. But I can imagine convertering sub to coo format, using np.argmax on the .data attribute, and with the corresponding row and col values, constructing a new matrix of the same shape but just one nonzero value.
If your blocks covered x in a regular, nonoverlapping manner, I'd suggest constructing a new matrix with sparse.bmat. That basically collects the coo attributes of all the components, joins them into one set of arrays with the appropriate offsets, and makes a new coo matrix.
If the blocks are scattered or overlap you might have to generate, and insert them back into x one by one. csr format should work for that, but it will issue a sparse efficiency warning. lil is supposed to be faster for changing values. I think it will accept blocks.
I can imagine doing this with sparse matrices, but it will take time to setup a test case and debug the process.
Thanks to hpaulj I managed to implement a solution using scipy.sparse.bmat:
from scipy.sparse import coo_matrix
from scipy.sparse import csr_matrix
from scipy.sparse import rand
from scipy.sparse import bmat
import numpy as np
np.set_printoptions(precision=2)
# my matrices are symmetric, so generate random symmetric matrix
x = rand(10,10,density=0.4)
x = x.T * x
x = x
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.unravel_index(sub.argmax(),sub.shape)
i1 = z[0]
j1 = z[1]
new = csr_matrix(([sub[i1,j1]],([i1],[j1])),shape=(b-a,d-c))
return new
def keep_all(a,b,c,d):
return x[a:b,c:d].copy()
# we want to create a chessboard pattern where the first central block is 1x1, the second 5x5 and the last 4x4
sizes = np.asarray([0,1,5,4])
sizes_sum = np.cumsum(sizes)
# acquire 2D array to store our chessboard blocks
r = range(len(sizes)-1)
blocks = [[0 for x in r] for y in r]
for i in range(1,len(sizes)):
current_i_min = sizes_sum[i-1]
current_i_max = sizes_sum[i]
for j in range(i,len(sizes)):
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
if i == j:
# keep the blocks at the diagonal completely
sub = keep_all(current_i_min, current_i_max, current_j_min, current_j_max)
blocks[i-1][j-1] = sub
else:
# the blocks not on the digonal only keep their maximum value
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
# we can leverage the matrix symmetry and only calculate one new matrix.
m1 = keep_only_max(current_i_min, current_i_max, current_j_min, current_j_max)
m2 = m1.T
blocks[i-1][j-1] = m1
blocks[j-1][i-1] = m2
z = bmat(blocks)
print(z.todense())

Multidimensional symbolic matrix in Python

I would like to create a 3D matrix of specific size by calculating a value for each combination of indexes. Each value in the matrix will be symbolic.
What I tried up to now:
import numpy as np
import sympy as sp
var1 = np.arange(1,10,2)
var2 = np.arange(1,10,2)
var3 = np.arange(20,50,5)
myMatrix = np.zeros(shape = (len(var1), len(var2), len(var3)))
t = sp.symbols('t')
for ii in range(len(var1)):
for jj in range(len(var2)):
for kk in range(len(var3)):
myMatrix[ii][jj][kk] = var1[ii] * var2[jj] * var3[kk] * t
This gives me the error:
TypeError: can't convert expression to float
which as far as I understand is due to combining numpy and sympy. Therefore, I tried:
myMatrix = sp.MatrixSymbol('temp', len(var1), len(var2), len(var3))
instead of:
myMatrix = np.zeros(shape = (len(var1), len(var2), len(var3)))
and got an error:
TypeError: new() takes exactly 4 arguments (5 given)
To sum up, my question is: how can I create a 3D matrix with any variables inside to be able to use it in the nested loop, which involves symbolic calculation?
(This is my first post in this community, so please let me know if I did anything wrong.)
The first error you get is, as you suggested, because you try to save a sympy type object into a numpy zeros array which is of type numbers. One option would be to use a numpy array of objects, which works as follows,
import numpy as np
import sympy as sp
var1 = np.arange(1,10,2)
var2 = np.arange(1,10,2)
var3 = np.arange(20,50,5)
myMatrix = np.empty((len(var1), len(var2), len(var3)), dtype=object)
t = sp.symbols('t')
for ii in range(len(var1)):
for jj in range(len(var2)):
for kk in range(len(var3)):
myMatrix[ii][jj][kk] = var1[ii] * var2[jj] * var3[kk] * t
Although for large sizes this isn't too efficient and not the way numpy should work. For sympy arrays this may be the only way to go however as it seems that, at least in my version of sympy (0.7.1.rc1), 3D arrays are not supported. For
myMatrix = sp.zeros((len(var1), len(var2), len(var3)))
I get the following error
ValueError: Matrix dimensions should be a two-element tuple of ints or a single int!

Categories