Jacobi Method & Basic Matrix Math using NUMPY - python

I'm getting an import error for "norm". What am I not doing correct??
I'm open to constructive feedback on improving the code, however I have to keep the parameters as they are!
Thanks!!!
Code is below:
import numpy as np
from numpy import norm, inalg, array, zeros, diag, diagflat, dot, linalg
"""Test Case Data"""
A = np.matrix([[4,-1,-1],[-2,6,1],[-1,1,7]])
b = np.matrix([[3],[9],[-6]])
x = np.matrix([[0],[0],[0]])
"""Main Function"""
def jacobi(A, b, x, Tolerance, Iterations):
V = np.diag(A)
D = np.diag(V)
R = D-A
D_I = D.I
D = np.asmatrix(D)
Counter_1 = 1
tol_gauge = 100
while Counter_1 <= Iterations:
# I considered using the "dot" function in NUMPY but I was wary of mixed results
iterative_approach_form = D_I * ((R*x)+b)
tol_gauge = np.linalg.norm(iterative_approach_form-x)
x = iterative_approach_form
if initial_tol <= Tolerance:
return("The Solution x = {},y={}, z={} ".format(x[0], x[1], x[2]))
return("The Solution was found in %s interation(s)" %(Counter_1))
else:
pass
Counter_1 +=1
return("The Solution was not found in {} iteration(s)".format(Iterations))

You need to specify which numpy module you are importing from. The following works if you want to use a function only by its name:
from numpy import linalg
from numpy.linalg import norm
from numpy import zeros, array, diag, diagflat, dot
Looking at you code however, you don't need the second import line, because in the rest of the code the numpy functions are specified according to the accepted norm. For example, norm is already present in your code as np.linalg.norm.
There are three more issues with your code: 1) initial_tol is not assigned a value; 2) tol_gauge is assigned but not used in the code; 3) the last return statement is not indented properly (perhaps only here) and the same is very likely for the block in your while loop.

Related

operation on Matrices with the elements in function form

I have a set of functions which are tended to be the elements of a matrix, and I have to do some + and * and / operation on them and also between each matrix element.
I am using Numpy, Sympy to do this and here is the code written on Python 2.7.
import numpy as np
import math
import cmath
import matplotlib.pyplot as pl
from cmath import*
from sympy import*
# delta, deltz and some other numbers are simple float number I changed varibles in for loop to the first value to test this section of my whole cod
f1 = Matrix([[1, 0],[ 0, 1]]) #an empty matrix from sympy
delta = 2.0*np.pi*1.6*((1.0/1530)-(1.0/(2.0*1550))) #this is a simple float number
deltz = (5*(10.0**6))/50
def apdFunc(x):
return np.exp(-2*np.log(2)*((x-(5/2))/5)**2)
def modFunc(x):
return (1+np.cos((2*np.pi/1)*x))
d1 = np.linspace(-20.0, 20.0, 5000)
apdFunc = apdFunc(d1)
modFunc = modFunc(d2)
Profile = modFunc*apdFunc
sig = (np.pi/1530)*fbgProfile + delta
kaa = (np.pi/1530)*fbgProfile
j = sqrt(-1)
gammab = np.sqrt(kaa**2.0-sig**2.0)
#Matrix elements definition
f11 = np.cosh(gammab*deltz)-1j*(sig/gammab)*np.sinh(gammab*deltz)
f22 = np.cosh(gammab*deltz)+1j*(sig/gammab)*np.sinh(gammab*deltz)
f12 = -1j*(kaa/gammab)*np.sinh(gammab*deltz)
f21 = 1j*(kaa/gammab)*np.sinh(gammab*deltz)
f1 = f1*Matrix([[f11, f12],[ f21, f22]])
PO=f1[0,0]
NO=f1[1,0]
REF=abs((NO/PO)**2)
pl.plot(d3,REF)
pl.show()
print f1[0,0]
print PO
print REF
The first problem is : gammab=np.sqrt(kaa**2.0-sig**2.0) that numpy can't accept complex number I mean negative value under sqrt and if I don't use Numpy I can't do Operation on them because kaa and sig are functions.
Second : I cant print the matrix elements (after reversing kaa**2.0-sig**2.0 and solving first problem), thus I can't plot the REF=abs((NO/PO)**2) and an error apears telling
AttributeError: 'ImmutableDenseNDimArray' object has no attribute 'as_coeff_Mul'
Any help appreciated and if you can introduce a reference to learn how to solve the problem.

Integration using trapezium method SciPy problems ('numpy.ndarray' object is not callable)

I'm trying to create a function that lets you input an expression for y with upper and lower bounds and N number of steps. It takes the expression, should integrate it and then run it through the trapezium method for N steps and spit out the result. Currently there is an error ('numpy.ndarray' object is not callable) in my way. Not sure how to fix it! Here's the code!
import numpy as np
import scipy.integrate as integrate
%matplotlib inline
def trap(f,b,a):
return 0.5 * (b-a)*(f(a) + f(b))
def multistep(f,method,b,a,N):
step = (b-a)/N
lower = np.linspace(b,a,N,endpoint=False)
upper = np.linspace(b+step,a,N)
result = 0
for n in range(N):
result += method(f,lower[n],upper[n])
return result
def trapezium_rule_integration_function(f,a,b,N):
x = np.linspace(b,a,N)
yf = []
for p in x:
yf.append(f(p))
y = np.array(yf)
return multistep(y,trap,b,a,N)
y = 1/(1+x**2)
trapezium_rule_integration_function(y,10,0,100)
Thank you in advance for any support available.
Johann Brahms
By looking quickly, I see that this error stems from the function trapezium_rule_integration_function,
y = np.array(yf)
return multistep(y,trap,b,a,N)
The first argument of multistep should be a function, but you provided an array y, which is not callable by '()'. This array is then passed to multistep, which expects a function f instead.
By the way, you should rewrite y as
y = lambda x: 1/(1+x**2)
Best of luck.

How to use Zero-skewness log transform in Python

How to do zero-skewness log transform in Python?
For example in Stata it is implemented in lnskew0 (see https://www.stata.com/manuals13/rlnskew0.pdf).
I didn't find an implementation in Python. Is anyone aware of an implementation?
Otherwise, a first try would be:
from scipy.stats import skew
import numpy as np
from scipy.optimize import root_scalar
def lnskew0(x):
def skew_ln(k):
return skew(np.log(x - k))
res = root_scalar(
skew_ln,
bracket=[-x.min(), x.max()*0.99999],
method='bisect'
)
return np.log(x - res.root)
Works fine on numpy arrays with only positive numbers. How is Stata's lnskew0 implemented that it works with negative numbers as well?
I gave it another try so that it works with negative numbers as well:
from scipy.stats import skew
import numpy as np
from scipy.optimize import root_scalar
def lnskew0(x):
x0 = x + 1
def skew_ln_pos(k):
with np.errstate(all='ignore'):
return skew(np.log(x0 - k))
res_pos = root_scalar(
skew_ln_pos,
bracket=[-150, 150],
method='bisect'
)
def skew_ln_neg(k):
with np.errstate(all='ignore'):
return skew(np.log(-x0 - k))
res_neg = root_scalar(
skew_ln_neg,
bracket=[-150, 150],
method='bisect'
)
res = (res_pos.root - 1, res_neg.root + 1)
lnskew0_res = (
np.log(x - res[0]),
np.log(-x - res[1])
)
whichmin = np.nanargmin([abs(skew(x)) for x in lnskew0_res])
return lnskew0_res[whichmin]
Note: It still has one issue. The bracket of the root_scalar needs to be choosen manually.

Python 3: Sympy: Include list information to optimize lambdify

I use lambdify to compile an expression which is a function of certain parameters. Each parameter has N points. So I need to evaluate the expression N times. The following shows a simplified example on how this is done.
import numpy as np
from sympy.parsing.sympy_parser import parse_expr
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy import S, Symbol
from sympy.utilities.autowrap import ufuncify
def CreateMagneticFieldsList(dataToSave,equationString,DSList):
expression = S(equationString)
numOfElements = len(dataToSave["MagneticFields"])
#initialize the magnetic field output array
magFieldsArray = np.empty(numOfElements)
magFieldsArray[:] = np.NaN
lam_f = lambdify(tuple(DSList),expression,modules='numpy')
try:
for i in range(numOfElements):
replacementList = np.zeros(len(DSList))
for j in range(len(DSList)):
replacementList[j] = dataToSave[DSList[j]][i]
try:
val = np.double(lam_f(*replacementList))
except:
val = np.nan
magFieldsArray[i] = val
except:
print("Error while evaluating the magnetic field expression")
return magFieldsArray
list={"MagneticFields":list(range(10000)), "Chx":list(range(10000))}
out=CreateMagneticFieldsList(list,"MagneticFields*5+Chx",["MagneticFields","Chx"])
print(out)
Is there a way to optimize this call further? Specifically, I mean is there a way to make lambdify include that I'm calculating for a list of points, so that the loop evalulation can be optimized?
Thanks to #asmeurer, he gave the idea on how to do it.
Since lambdify is compiled using numpy, then one could simply pass the lists as arguments! The following is a working example
#!/usr/bin/python3
import numpy as np
from sympy.parsing.sympy_parser import parse_expr
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy import S, Symbol
from sympy.utilities.autowrap import ufuncify
def CreateMagneticFieldsListOpt(dataToSave,equationString,DSList):
expression = S(equationString)
numOfElements = len(dataToSave["MagneticFields"])
#initialize the magnetic field output array
magFieldsArray = np.empty(numOfElements)
magFieldsArray[:] = np.NaN
lam_f = lambdify(tuple(DSList),expression,modules='numpy')
replacementList = [None]*len(DSList)
for j in range(len(DSList)):
replacementList[j] = np.array(dataToSave[DSList[j]])
print(replacementList)
magFieldsArray = np.double(lam_f(*replacementList))
return magFieldsArray
list={"MagneticFields":[1,2,3,4,5],"ChX":[2,4,6,8,10]}
out=CreateMagneticFieldsListOpt(list,"MagneticFields*5+ChX",["MagneticFields","ChX"])
print(out)

Python's random module made inaccessible

When I call random.sample(arr,length) an error returns random_sample() takes at most 1 positional argument (2 given).I've tried importing numpy under a different name, which doesn't fix the problem.Any thoughts? Thanks
import numpy.random
import random
import numpy as np
from numpy import *
points = [[1,1],[1.5,2],[3,4],[5,7],[3.5,5],[4.5,5], [3.5,4]]
def cluster(X,center):
clusters = {}
for x in X:
z= min([(i[0], np.linalg.norm(x-center[i[0]])) for i in enumerate(center)], key=lambda t:t[1])
try:
clusters[z].append(x)
except KeyError:
clusters[z]=[x]
return clusters
def update(oldcenter,clusters):
d=[]
r=[]
newcenter=[]
for k in clusters:
if k[0]==0:
d.append(clusters[(k[0],k[1])])
else:
r.append(clusters[(k[0],k[1])])
c=np.mean(d, axis=0)
u=np.mean(r,axis=0)
newcenter.append(c)
newcenter.append(u)
return newcenter
def shouldStop(oldcenter,center, iterations):
MAX_ITERATIONS=0
if iterations > MAX_ITERATIONS: return True
u=np.array_equal(center,oldcenter)
return u
def init_board(N):
X = np.array([(random.uniform(1,4), random.uniform(1, 4)) for i in range(4)])
return X
def kmeans(X,k):
clusters={}
iterations = 0
oldcenter=([[],[]])
center = random.sample(X,k)
while not shouldStop(oldcenter, center, iterations):
# Save old centroids for convergence test. Book keeping.
oldcenter=center
iterations += 1
clusters=cluster(X,center)
center=update(oldcenter,clusters)
return (center,clusters)
X=init_board(4)
(center,clusters)=kmeans(X,2)
print "center:",center
#print "clusters:", clusters
When you use from numpy import * you import all items that are in the numpy namespace into your scripts namespace. When you do this any functions/variables/etc that have the same name will be overwritten by the items from the numpy namespace.
numpy has a subpackage called numpy.random which then overwrote your random import as the code below shows:
import random
# Here random is the Python stdlib random package.
from numpy import *
# As numpy has a random package, numpy.random,
# random is now the numpy.random package as it has been overwritten.
In this case you should instead use import numpy as np which will allow you to access both:
import random
# random now contains the stdlib random package
import numpy as np
# np.random now contains the numpy.random package
Your points is List type, so you should convert it to an array
points = np.asarray(point)
Also, you should use import random

Categories

Resources