Export a matrix with symbolic variables from Matlab to Python - python

I have a matrix with symbolic variable in MATLAB like this:
syms x
f = [x^2 x^3 x^4];
save ('sym.mat','f')
Thus I saved the f matrix as sym.mat. Now I want to import this matrix into python. So I tried this:
import scipy.io as sio
matrix = sio.loadmat('sym.mat')
sym = matrix['f']
But it didn't work. I got this error, which is just a regular python keyerror.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'f'
However if f is not a symbolic matrix then this code works fine. Any ideas how I can deal with these matrices with symbolic variables?

Scipy can't load MATLAB symbolic variables.
The best way to deal with your problem is to convert your Symbolic matrix into Matrix of chars(not matlab strings since it will cause errors too)
So here is what I mean:
In MATLAB, you can do something like that:
syms x
f = [x^2 x^3 x^4];
for i = 1:numel(f)
if i == 1
f2 = char(f(i));
else
f2 = [f2 ',' char(f(i))];
end
end
save('sym.mat','f2')
This will display:
x^2,x^3,x^4
Now, In python you could do something like that:
import scipy.io as sio
path = 'H:\MatlabScripts'
matrix = sio.loadmat(path + '\sym.mat')
sym = matrix['f2'][0].split(',')
print(sym)
The result will be:
['x^2', 'x^3', 'x^4']

Related

How to subsitute symbols in sympyfied expression properly?

my goal is to have a string turned into a symbolic expression using sympify and then make substitutions.
import sympy as sp
Eq_Str = 'a*x+b'
Eq_Sym = sp.sympify(Eq_Str)
Then, for instance, substitute a for something else:
Eq_Sym.subs(a,2)
But I get the error:
Traceback (most recent call last):
File "<ipython-input-5-e9892d6ffa06>", line 1, in <module>
Eq_Sym.subs(a,2)
NameError: name 'a' is not defined
I understand that there is no symbol a in the workspace. Am I right?
Is there a way to get the symbols from the set I get from Eq_Sym.free_symbols into the workspace so I can substitute them in Eq_Sym.
Thank you very much for taking the time to read this.
you can use globals() for that:
import sympy as sp
Eq_Str = 'a*x+b'
Eq_Sym = sp.sympify(Eq_Str)
for s in Eq_Sym.free_symbols :
globals()[s.name] = s;
print (Eq_Sym.subs(a,2)); #b + 2*x

odeint -(TypeError: can't convert expression to float ) - Importing expression into a function to perform odeint

This is the error I get
Traceback (most recent call last):
File "C:\Users\user\.spyder-py3\Numerical Methods Problems\FreeFall.py", line 40, in <module>
ans=odeint(vel,0,t)
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\integrate\odepack.py", line 245, in odeint
int(bool(tfirst)))
File "C:\ProgramData\Anaconda3\lib\site-packages\sympy\core\expr.py", line 325, in __float__
raise TypeError("can't convert expression to float")
TypeError: can't convert expression to float
And Here is my code - I am pretty new to coding and am learning to use it for numerical computation:
from scipy.integrate import odeint
from sympy import *
import numpy as np
import math
def diff_cd(re_no):
Re=Symbol('Re')
expr=(24/Re)+(6/(1+(Re**0.5)))+0.4
ans=diff(expr,Re).subs(Re,re_no)
return ans
def diff_re(k,u_no):
u=Symbol('u')
expr=k*u
ans=diff(expr,u).subs(u,u_no)
return ans
ans = [diff_cd(20),diff_re(11,15)]
rhog=1.2
mug=1.872*(10**(-5))
a=0.3
u=Symbol('u')
pi=math.pi
k=(2*rhog*a/mug)
Re=k*u
p1=(rhog*pi*(a**2)*u*Re*((24/Re)+(6/(1+(Re**0.5)))+0.4))+(0.5*rhog*pi*(a**2)*(u**2)*diff_cd(Re)*diff_re(k,u))
ansfu=p1*(-1/24)
def vel(y,t):
dudt = ansfu
return dudt
t=np.linspace(1,100,100)
ans=odeint(vel,0,t)
print(ans)
I just need is to get an answer without this error. Also is there a way to do all this in a single function
If I add a print(vel(0,0)) before the ode call I get
-271.868595022194*u**2*(-3.97723522060237e-7*u**(-0.5)/(u**0.5 +
0.00509901951359279)**2 - 1.6224e-8/u**2) -
543.737190044387*u**2*(0.4 + 6/(196.116135138184*u**0.5 + 1) + 0.000624/u)
That is, a sympy expression, not a number. odeint cannot work with that!
u is defined as Symbol, and thus any python expression using it will also be a sympy expression.
Especially if you are new to coding, you should stick with one package or the other. If defining the function symbolically, then use sympy and its own solvers. But if a numeric solution of the kind that scipy produces is important, then define the function with python/numpy. Don't try to mix sympy and numpy (without a lot more experience).
Old question but it seems you could've solved this problem using sympy's lambdify function. You'd do it like this:
f = lambdify(x, x**2, modules=['scipy'])
now f is a lambda that you can use with scipy.

TypeError: only size-1 arrays can be converted to Python scalars - Earth Observation

I'm attempting to create a script that will take a .GTiff file as an argument input and then extract some information out of the file to create a stats.txt file that will give me the classID, fractional coverage and total number of pixels of that classID.
Thus far I believe I have everything I need but I keep running into the same error and my attempts to rectify the error haven't proven to be very fruitful.
#!/usr/bin/env python
import sys
import calendar
import os
import gdal
import numpy as np
from scipy.stats import mode
from IPython import embed
GDAL2NUMPY = { gdal.GDT_Byte : np.uint8,
gdal.GDT_UInt16 : np.uint16,
gdal.GDT_Int16 : np.int16,
gdal.GDT_UInt32 : np.uint32,
gdal.GDT_Int32 : np.int32,
gdal.GDT_Float32 : np.float32,
gdal.GDT_Float64 : np.float64,
gdal.GDT_CInt16 : np.complex64,
gdal.GDT_CInt32 : np.complex64,
gdal.GDT_CFloat32 : np.complex64,
gdal.GDT_CFloat64 : np.complex128
}
#Open the original training data .tif map file.
fname = sys.argv[1]
lc_dataset = gdal.Open(fname)
lc = lc_dataset.ReadAsArray()
lc = np.array(lc)
#Calculating total number of pixels with a valid Land Cover ID.
fill_value = 0
number_of_pixels = np.where(lc != fill_value)[0].shape[0]
#Get the number of classes and corresponding IDs.
lc_classes = np.unique(lc)
#Split each class into its contituante pixel and write result to file.
for classID in range(1, lc_classes):
lc_class_pixels = np.where(lc == classID)[0].shape[0]
FractionalCover = lc_class_pixels/number_of_pixels
f.write(classID, FractionalCoverage, lc_class_pixels)
f.close()
When I run this, it chuck up the following traceback:
Traceback (most recent call last):
File "GeneratingLCstats.py", line 45, in <module>
for classID in range(1, lc_classes):
TypeError: only size-1 arrays can be converted to Python scalars
I've attempted a few changes as I'm sure the error is related to numpy data and native python data interactions, but converting all my arrays to numpy arrays and attempting to reformat the code has proved in vain as the same error persists.
If anyone can suggest a fix that would be greatly appreciated!
Thanks.
Well, the function lc_classes = np.unique(lc) returns an array. When you try to write the for loop as
for classID in range(1, lc_classes)
Here, lc_classes is an array and trying to give it as a bound for the range causes the error. If you want to iterate over the length of the array, you can modify the code to :
for classID in range(1, len(lc_classes))

mpmath laplace inverse function in python

I am trying to find the laplace inverse of an expression for which all but one variable are already defined at the time of declaration:
from numpy import *
import mpmath as mp
p0 = 1
E = 2
c= 3
L = 4
x = 2.5
t = linspace(1,5,10)
ulaplace = []
def U(s):
return(c*p0*(-exp(L*s/c) + exp(s*(L + 2*x)/c))*exp(-s*x/c)/(E*s**2*(exp(2*L*s/c) + 1)))
for ti in t:
ulaplace.append(mp.invertlaplace(U, ti, method='talbot'))
But I am getting this error:
Traceback (most recent call last):
File "D:\TEMP\IDLEscripts\CompareAnalyticalSolutions2.py", line 46, in <module>
ulaplace.append(mp.invertlaplace(U, ti, method='talbot'))
File "C:\Python35\lib\site-packages\mpmath\calculus\inverselaplace.py", line 805, in invertlaplace
fp = [f(p) for p in rule.p]
File "C:\Python35\lib\site-packages\mpmath\calculus\inverselaplace.py", line 805, in <listcomp>
fp = [f(p) for p in rule.p]
File "D:\TEMP\IDLEscripts\CompareAnalyticalSolutions2.py", line 43, in U
return(c*p0*(-exp(L*s/c) + exp(s*(L + 2*x)/c))*exp(-s*x/c)/(E*s**2*(exp(2*L*s/c) + 1)))
TypeError: attribute of type 'int' is not callable
I also tried the lambda function format suggested by the doc website but still got the same error.
Does the mpmath.invertlaplace function require that everything be in numerical termsat the time of definition? I am asking because this worked:
>>> import mpmath as mp
>>> def F(s):
return 1/s
>>> mp.invertlaplace(F,5, method = 'talbot')
mpf('1.0')
If so, I need to be able to circumvent this. The whole point for me is to play around with the other variables and see how they affect the inverse laplacian. Furthermore one would think that the function gets evaluated before it is passed on to mpmath.
If not, then what on earth is going on here?
Allright I got it. Basically the function that mp.invertlaplace needs to itself only use mpmath defined functions. In the code provided in the original question I am using exp from the numpy library. So exp(x) is really numpy.exp(x). To make the code work it needs to call the mpmath.exp function as follows:
def U(s):
return -p0*mp.exp(s*x/c)/(E*s*(-s*mp.exp(L*s/c)/c - s*mp.exp(-L*s/c)/c)) + p0*mp.exp(-s*x/c)/(E*s*(-s*mp.exp(L*s/c)/c - s*mp.exp(-L*s/c)/c))
I have not tested the above on the reduced example I provided in the original question, since it is a subset of the more general script. However it should work and this appears to be the root of the problem.

matrix multiplication with oct2py

I am using oct2py to run octave function with python.
It is working but I get an error when I try to multiply 2 matrix.
What can I do to solve the problem?
this is a sample matlab funcion
%% MATLAB
function lol = jk2(arg1,arg2)
arg1 = arg1;
arg2 = arg2;
lol = arg1*arg2;
end
this is the code to call the function
import oct2py
from oct2py import octave
a=3
b=4
octave.call("/MATLAB/jk2.m",a,b) # this call works
a=np.array([[1,2],[3,4]])
b=np.array([[5,6],[1,2]])
octave.call("/MATLAB/jk2.m",a,b) # this call report an errors
This is the error message
>>> octave.call("/home/donbeo/Documents/MATLAB/jk2.m",a,b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/oct2py-1.2.0-py2.7.egg/oct2py/session.py", line 210, in call
resp = self._eval(cmd, verbose=verbose)
File "/usr/local/lib/python2.7/dist-packages/oct2py-1.2.0-py2.7.egg/oct2py/session.py", line 350, in _eval
return self._session.evaluate(cmds, verbose, log, self.logger)
File "/usr/local/lib/python2.7/dist-packages/oct2py-1.2.0-py2.7.egg/oct2py/session.py", line 523, in evaluate
raise Oct2PyError(msg)
oct2py.utils.Oct2PyError: Oct2Py tried to run:
"""
[a__] = jk2(A__, B__)
"""
Octave returned:
binary operator '*' not implemented for 'int64 matrix' by 'int64 matrix' operations
>>>
Here is an example of where the line between Python and Octave gets blurry. Numpy interprets your arrays as being of integer type (because there are no explicit floats), but Octave would treat the arrays as Doubles. If you add a period anywhere in you array definitions, it will all work.
Fixed (tested) example:
from oct2py import octave
import numpy as np
a = np.array([[1, 2], [3, 4.]]) # notice the addition of the period
b = np.array([[5, 6], [1, 2], dtype=float]) # another way to specify floating point type
octave.call("/MATLAB/jk2.m", a, b) # this call works just fine

Categories

Resources