I have a python code within which I want to manipulate a list using a Matlab function and return it as a new list to python.
To test matlab.engine, I've tried the following:
import matlab.engine
eng = matlab.engine.start_matlab()
eng.cd('~/Documents/someDirWithMatlabFunctions/')
a = testFnc(2)
where testFnc.m looks like
function [list2] = testFnc(list)
for i = 1:numel(list)
list(i) = 3*list(i)
end
list2 = list;
end
When I run the python code, I get the following output:
>>> a = eng.testFnc(4)
>>> a
12L
>>> print a
12
My first question is what is 12L? Furthermore, when I try to pass a list as an argument:
>>> a = eng.testFnc([1,2,3])
Undefined function 'mtimes' for input arguments of type 'cell'.
It then references the line of the Matlab function in which the multiplication takes place, as where the error occurs.
I had anticipated that this might be a problem, as lists and matrices are different things. How can I properly pass variables to and from Matlab?
What is 12L?
Python supports arbitrary precision integers, meaning you're able to represent larger numbers than a normal 32- or 64-bit integer type. The L tells you when a literal is of this type and not a regular integer.
Note, that L only shows up in the interpreter output, it's just signifying the type. That's why it doesn't show up when you print it.
How can I properly pass variables to and from Matlab?
Straight from MathWorks documentation:
The matlab Python package provides array classes to represent arrays of MATLAB numeric types as Python variables so that MATLAB arrays can be passed between Python and MATLAB.
The documentation goes on to give lots of helpful examples for how to pass variables from MATLAB.
To pass data back to MATLAB, I recommend using numpy/scipy. This answer explains more about how to do that.
Related
I have a function that converts a value in one format to another. It's analogous to converting Fahrenheit to Celsius for example.
Quite simply, the formula is:
l = -log(20/x)
I am inheriting SAS code from a colleague that has the following hardcoded for a range of values of x:
"if x= 'a' then x=l;"
which is obviously tedious and limited in scope.
How best could I convert this to a function that could be called in a SAS script?
I previously had it in Python as:
def function(x):
l = -np.log10(20/float(x))
return l
and then would simply call the function.
Thank you for your help - I'm adusting from Python to SAS and trying to figure out how to make the switch.
If you are interested in writing your own functions, as Joe said, proc fcmp is one way to do it. This will let you create functions that behave like SAS functions. It's about as analogous to Python functions as you'll get.
It takes a small bit of setup, but it's really nice in that the functions are all saved in a SAS dataset that can be transferred from environment to environment.
The below code creates a function called f() that does the same as the Python function.
proc fcmp outlib=work.funcs.log;
function f(x);
l = log10(20/x);
return(l);
endfunc;
run;
options cmplib=work.funcs;
This is doing three things:
Creating a function called f() that takes one input, x
Saving the function in a dataset called work.funcs that holds all functions
Labeling all the functions under the package log
Don't worry too much about the label. It's handy if you have many different function packages you want, for example: time, dates, strings, etc. It's helpful for organization, but it is a required label. Most of the time I just do work.funcs.funcs.
options cmplib=work.funcs says to load the dataset funcs which holds all of your functions of interest.
You can test your function below:
data test;
l1 = f(1);
l2 = f(2);
l10 = f(10);
run;
Output:
l1 l2 l10
1.3010299957 1 0.3010299957
Also, SAS does have a Python interface. If you're more comfortable programming in Python, take a look at SASPy to get all the benefits of both SAS and Python.
The typical way you'd do this is in a SAS Macro.
%macro func(x);
-log10(20/&x)
%mend func;
data whatever;
set yourdataset;
l = %func(x);
run;
You can also of course just directly use it in code if it's trivial like this.
data whatever;
set yourdataset;
l = -log10(20/x);
run;
There are actual functions in SAS, but they're not really used very commonly. FCMP is the procedure where you construct those. Unfortunately, they're less efficient than macros or directly writing the code.
To convert your IF/THEN statements typically I would recommend a Format/Informat for SAS. Your code as shown isn't likely to work as you're also converting types (Character to Numeric).
*maps old values to new values;
*can be created from a data set as well;
proc format;
invalue myXfmt
'a' = 1
'b' = 2
'c' = 3;
*create sample data;
data have;
input x $;
cards;
a
b
c
;;;;
run;
data want;
set have;
*does the conversion;
x1= input(x, myxfmt.);
run;
*display for output;
proc print data=want;
run;
For more information I recommend this paper.
I am currently trying to pass a string to a Fortran library. I have gotten other functions from this library to work, but this particular one seems to be unique in that it wants a string passed to it as an argument to the function.
Looking at the source code, the function requires three arguments
SUBROUTINE EZVOLLIB(VOLEQI,DBHOB,HTTOT,VOL)
and the arguments are defined:
IMPLICIT NONE
CHARACTER*(*) VOLEQI
CHARACTER*10 VOLEQ
REAL DBHOB,HTTOT,TOPD, VOL(15), MHT
INTEGER REGN,ERRFLG
In Python my call to the function looks like
from ctypes import *
mylib = cdll.LoadLibrary('/home/bryce/Programming/opencompile/libvollib.so')
dbhob = c_float(42.2)
vol = (c_float * 15)()
voleqi = c_char_p("101DVEW119 ")
mylib.ezvollib_(voleqi, dbhob, vol)
This runs without a segmentation fault, but does not seem to "fill" the variable vol with the desired 15 float values.
Is there any way to get vol to retrieve the values being returned from the EZVOLLIB function?
There are many similar questions here, but it is hard to find an exact duplicate. There are several possible ways to do that with different degrees of universal correctness and portability.
The most correct way is to use modern Fortran to C interoperability as explained in fortran77, iso_c_binding and c string That requires writing more Fortran wrapping code.
There are people who are strictly against writing any more Fortran, even-though that is the only portable solution. In that case they must explore what is the actual calling convention for Fortran strings in their compiler. Usually a hidden integer argument with the string length is passed to the subroutine. For gfortran see https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html
Your ctypes interface could employ these compiler-specific calling conventions but then the interface will be, well, compiler-specific. But you are already relying on the specific name mangling ezvollib_ and that is compiler-specific as well. You can find examples here on SO where people were bitten by relying on that.
Also note, as noted by High Performance Mark, that the subroutine in question has four arguments, not three: EZVOLLIB(VOLEQI,DBHOB,HTTOT,VOL). Calling it with just three as in mylib.ezvollib_(voleqi, dbhob, vol) is an error. You are missing the HTTOT argument.
I have a problem when using the MATLAB python engine.
I want to get approximated solutions to ODEs (using something like the ode45 function in MATLAB) from Python, but the problem is that ODE approximation requires an ODE function specification that I can't seem to create from the MATLAB Python engine.
It works fine calling MATLAB functions, such as isprime, from Python but there seems to be no way of specifying a MATLAB function in Python.
My question is therefore;
Are there any way of generating MATLAB function code from Python or is a way to specify MATLAB functions from Python?
odefun passed to ode45, according to docs, has to be a function handle.
Solve the ODE
y' = 2t
Use a time interval of [0,5] and the initial condition y0 = 0.
tspan = [0 5];
y0 = 0;
[t,y] = ode45(#(t,y) 2*t, tspan, y0);
#(t,y) 2*t returns a function handle to anonymous function.
Unfortunately, function handles are listed as one of datatypes unsupported in MATLAB <-> Python conversion:
Unsupported MATLAB Types The following MATLAB data types are not supported by the MATLAB Engine API for Python:
Categorical array
char array (M-by-N)
Cell array (M-by-N)
Function handle
Sparse array
Structure array
Table
MATLAB value objects (for a discussion of handle and value classes see Comparison of Handle and Value Classes)
Non-MATLAB objects (such as Java® objects)
To sum up, it seems like there is no straightforward way of doing it.
Potential workaround may involve some combination of engine.workspace and engine.eval, as shown in Use MATLAB Engine Workspace in Python example.
Workaround with engine.eval (first demo):
import matlab.engine
import matplotlib.pyplot as plt
e = matlab.engine.start_matlab()
tr, yr = e.eval('ode45(#(t,y) 2*t, [0 5], 0)', nargout=2)
plt.plot(tr, yr)
plt.show()
By doing so, you avoid passing function handle via MATLAB/Python barrier. You pass string (bytes) and allow MATLAB to evaluate it there. What's returned is pure numeric arrays. After that, you may operate on result vectors, e.g. plot them.
Since passing arguments as literals would quickly became pain, engine.workspace may be used to avoid it:
import matlab.engine
import matplotlib.pyplot as plt
e = matlab.engine.start_matlab()
e.workspace['tspan'] = matlab.double([0.0, 5.0])
e.workspace['y0'] = 0.0
tr, yr = e.eval('ode45(#(t,y) 2*t, tspan, y0)', nargout=2)
plt.plot(tr, yr)
plt.show()
Now I am trying to rewrite the fortran code to python script.
In original fortran code, it declares real number as:
real a(n),b(n),D(64)
Here how can I convert this D(64) in python code?
a(n), b(n) are values from the data which I used, but D(64) is not.
I need to put this into sub-module fortran code which I wrapped with f2py.
That sub-module code looks like below. M is just a integer which will be define in main code.
subroutine multires (a,b,M, D)
implicit none
real a(*),b(*),D(*)
.
.
if(nw.gt.1) D(ms+1)=(sumab/nw)
If you code is looking for good performance, stay away from python lists. Instead you want to use numpy arrays.
import numpy as np
D = np.zeros((64), np.float32)
This will construct a numpy ndarray with 64 elements of 32 bit reals initialized to 0. Using these kind of arrays rather than lists can greatly improve the performance of your python code over lists. They also give you finer control over the typing for interoperability and you incur less overhead, especially if you get into cython.
Python is dynamically typed, so you have not to declare variables with their type. A Fortran array can be translated in a Python list, but as you should not want to dynamically add elements to the list, you should initialize it to its size. So Fortran real D(64) could become in Python:
D = [ 0. for i in range(64) ]
(declares D to be a list and initializes it with 64 0. values)
Of course, if you can use numpy and not just plain Python, you could use numpy.array type. Among other qualities (efficiency, type control, ...), it can be declared with F (for Fortran) order, meaning first-index varies the fastest, as Fortran programmers are used to.
This question already has answers here:
Simulating Pointers in Python
(11 answers)
Closed 9 years ago.
I'm a physics student, mostly programming in Python and Matlab, now getting into C to boost the performance of my simulations.
Simple question: are there pointers in Python? Are there pointers in Matlab? If yes, can I use them with similar "ease" as in C?
I know that behind the high-levelness in Python and Matlab, there are lots of pointers at work. The question is: can I do something like this C code explicitly in Python or Matlab:
int *p;
int someValue = 1;
p = &someValue;
doSomethingForMe = callSomeFunction(p);
I know there's probably no point in doing that anyway (for most applications). I just want to learn.
You will commonly hear that Python has names, not "variables" in the traditional sense. It also doesn't have "pointers" since such a concept is only meaningful when working at a low level, like with C. (For this reason, you can get "pointers" if you use a C compatibility library in Python, like ctypes. But, such pointers are meant only for interoperability with C.)
Most of the functionality you would use a pointer for in C is present in some other form in Python. For example:
Returning multiple values from a function. In C, you'd do int foo(int *, int *) to return two ints (and maybe an error code). In Python, just use tuple unpacking: x, y = foo() with return x, y in foo.
Passing in big objects. Since everything is pass-by-reference anyway, you can safely pass a reference to a huge object without having it get copied.
Modifying input parameters. Most of this is possible by choosing an appropriate mutable input. For example, you can pass a list into a function and modify the list within the function. In Python, since the references are the same, the input list will appear to be modified:
def change_list(l):
l[0] = 3
my_list = [1,2,3]
change_list(my_list)
print(my_list) # prints [3, 2, 3]
MATLAB has a different concept of variable than Python does. In MATLAB, a variable is a matrix with some dimensions. Writing x = y effectively copies y into x (setting xs dimensions appropriately). MATLAB internally does optimizations to avoid actually copying data unless necessary, but for the programmer it will seem as if x and y are separate matrices.
MATLAB also doesn't have pointers unless you are dealing with a compiled MEX extension (which is written in some other language like C). Like Python, you have mechanisms for passing things around without needing pointers (multiple input and output arguments, for example).
Python you can have pointers with ctypes library apparently. Also, you can simulate the notion of pointers in Python, like in this question.
In Matlab you don't have pointers either.