f2py won't compile with negative indexes for vector parameter - f2py

Say I have a module to be compiled via f2py:
test.f90
module test
implicit none
integer, parameter :: q = 2
real(8), parameter, dimension(-q:q) :: vec = (/ 1, 2, 3, 4, 5 /)
contains
subroutine writevec()
write(*,*) vec
end subroutine
end module
Upon running f2py -c -m test test.f90, I get the error
/tmp/tmp6X6gsD/src.linux-x86_64-2.7/testmodule.c:176:17: error: expected expression before ‘)’ token
{"vec",1,{{-(-)+1}},NPY_DOUBLE},
On the other hand, if I declare vec with dimension(2*q+1), it works. Sort of. When I import into python:
>>> from test import test
>>> test.writevec()
>>> 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000
>>> test.vec
>>> array([ 1., 2.]) # ???
What is going on here??

You can create a signature file in order to get the array dimensions right. This creates the signature file 'sign.pyf' for the python module 'mymod':
f2py -m mymod -h sign.pyf test.f90
Then, use this to compile:
f2py -c sign.pyf test.f90
The library can be imported and used in Python as:
>>>import mymod
>>>mymod.test.writevec()
Note, that the array bounds are shifted and the first element has the index 0 in Python:
>>>import mymod
>>>mymod.test.vec #output: array([ 1., 2., 3., 4., 5.])
>>>mymod.test.vec[0] #output: 1.0

Related

Memoryviews slices in Cython ask for a scalar

I'm trying to create a memoryview to store several vectors as rows, but when I try to change the value of any I got an error, like it is expecting a scalar.
%%cython
import numpy as np
cimport numpy as np
DTYPE = np.float
ctypedef np.float_t DTYPE_t
cdef DTYPE_t[:, ::1] results = np.zeros(shape=(10, 10), dtype=DTYPE)
results[:, 0] = np.random.rand(10)
This trows me the following error:
TypeError: only size-1 arrays can be converted to Python scalars
Which I don't understand given that I want to overwrite the first row with that vector... Any idea about what I am doing wrong?
The operation you would like to use is possible between numpy arrays (Python functionality) or Cython's memory views (C functionality, i.e. Cython generates right for-loops in the C-code), but not when you mix a memory view (on the left-hand side) and a numpy array (on the right-hand side).
So you have either to use Cython's memory-views:
...
cdef DTYPE_t[::1] r = np.random.rand(10)
results[:, 0] = r
#check it worked:
print(results.base)
...
or numpy-arrays (we know .base is a numpy-array):
results.base[:, 0] = np.random.rand(10)
#check it worked:
print(results.base)
Cython's version has less overhead, but for large matrices there won't be much difference.

#cython.locals(arr=np.ndarray[np.int_t, ndim=1]) not supported?

It seems that one can't declare np.ndarray in cython.locals in .pxd files. It works with memoryviews but not with np.ndarray. However, there are cases where we need np.ndarray.
In notsupported.py
import numpy as np
def func():
arr = np.ones(2)
return arr**2
In notsupported.pxd
import cython
import numpy as np
cimport numpy as np
#cython.locals(arr=np.ndarray[np.int_t, ndim=1])
cpdef func()
Error log:
Error compiling Cython file:
------------------------------------------------------------
...
import cython
import numpy as np
cimport numpy as np
#cython.locals(arr=np.ndarray[np.int_t, ndim=1])
^
------------------------------------------------------------
notsupported.pxd:6:44: Expected ']', found '='
Is there something wrong with this code? What is the alternative?
Since it looks like this isn't supported I assume you're really interested in workarounds. For the purpose of this question I'm assuming you want your code to also be valid in pure Python. I'm also assuming that your code is of the form:
def func():
arr = np.ones(2)
for n in range(arr.shape[0]):
arr[n] = # some operation element-by-element
return arr**2
If your code doesn't have the element-by-element section then there's really no benefit to setting the type at all - I don't believe Cython uses the type for Numpy "whole array" operations like the power operator you show here.
My first choice would be to have two variables: arr and arr_view. arr should be untyped, and arr_view a memoryview. You only use the memoryview in the element-by-element section. Provided you stick to in-place operations the two share the same memory so modifying one modifies the other:
def func():
arr = np.ones(2)
arr_view = arr
for n in range(arr_view.shape[0]):
arr_view[n] = ...
return arr**2
The pxd file is then:
#cython.locals(arr_view=np.int_t[:])
cpdef func()
My second choice would be to type arr as a memoryview, and use np.asarray when you want to do "whole array" operations
def func():
arr = np.ones(2)
for n in range(arr.shape[0]):
arr[n] = # some operation element-by-element
return np.asarray(arr)**2
with pxd:
#cython.locals(arr=nnp.int_t[:])
cpdef func()
np.asarray is essentially a no-op if it's passed an array, and can usuaully avoid a copy if passed a memoryview, so it won't slow things down too much.
A third option is to use the arr.base object of a memoryview to get the underlying Numpy array. This loses pure Python compatibility though since arr.base is often None when arr is a Numpy array. Therefore I don't really recommend it here.

couldn't match type 'ByteString o0 m0 Value' Vs 'ByteString Data.Void.Void IO Value'

I am trying the haskell-json-service. When I run the code, it throws error here:
app req sendResponse = handle (sendResponse . invalidJson) $ do
value <- sourceRequestBody req $$ sinkParser json
newValue <- liftIO $ modValue value
sendResponse $ responseLBS
status200
[("Content-Type", "application/json")]
$ encode newValue
Error is,
Couldn't match type ‘conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
ByteString o0 m0 Value’
with ‘conduit-1.2.4.1:Data.Conduit.Internal.Conduit.ConduitM
ByteString Data.Void.Void IO Value’
NB: ‘conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM’
is defined in ‘Data.Conduit.Internal.Conduit’
in package ‘conduit-1.2.4’
‘conduit-1.2.4.1:Data.Conduit.Internal.Conduit.ConduitM’
is defined in ‘Data.Conduit.Internal.Conduit’
in package ‘conduit-1.2.4.1’
Expected type: conduit-1.2.4.1:Data.Conduit.Internal.Conduit.Sink
ByteString IO Value
Actual type: conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
ByteString o0 m0 Value
In the second argument of ‘($$)’, namely ‘sinkParser json’
In a stmt of a 'do' block:
value <- sourceRequestBody req $$ sinkParser json
What does double dollar do? And what is this type - ByteString o0 m0 Value?
This appears to be the problem:
conduit-1.2.4:...
conduit-1.2.4.1:...
Your code is using a ByteString type from two different versions of the conduit library. From the point of view of GHC, these two types are unrelated: for instance, you can not pass the first type to a library function which expects the second one.
A cause for this could be using a library X which was compiled against the "old" conduit and a library Y which instead was compiled against the newer version. If your program imports X and Y, you will get in trouble when passing bytestrings from X to Y or vice versa. I have no idea about what X or Y actually are.
Maybe you can recompile X or Y so that they use the same version of conduit.

Program Works in Python 2.7, but not Python 3.3 (Syntax is compatible for both)

So I have the function integral(function, n=1000, start=0, stop=100) defined in nums.py:
def integral(function, n=1000, start=0, stop=100):
"""Returns integral of function from start to stop with 'n' rectangles"""
increment, num, x = float(stop - start) / n, 0, start
while x <= stop:
num += eval(function)
if x >= stop: break
x += increment
return increment * num
However, my teacher (for my Programming class) wants us to create a separate program that gets the input using input() and then returns it. So, I have:
def main():
from nums import integral # imports the function that I made in my own 'nums' module
f, n, a, b = get_input()
result = integral(f, n, a, b)
msg = "\nIntegration of " + f + " is: " + str(result)
print(msg)
def get_input():
f = str(input("Function (in quotes, eg: 'x^2'; use 'x' as the variable): ")).replace('^', '**')
# The above makes it Python-evaluable and also gets the input in one line
n = int(input("Numbers of Rectangles (enter as an integer, eg: 1000): "))
a = int(input("Start-Point (enter as an integer, eg: 0): "))
b = int(input("End-Point (enter as an integer, eg: 100): "))
return f, n, a, b
main()
When run in Python 2.7, it works fine:
>>>
Function (in quotes, eg: 'x^2'; use 'x' as the variable): 'x**2'
Numbers of Rectangles (enter as an integer, eg: 1000): 1000
Start-Point (enter as an integer, eg: 0): 0
End-Point (enter as an integer, eg: 100): 100
Integration of x**2 is: 333833.5
However, in Python 3.3 (which my teacher insists we use), it raises an error in my integral function, with the same exact input:
Traceback (most recent call last):
File "D:\my_stuff\Google Drive\documents\SCHOOL\Programming\Python\Programming Class\integration.py", line 20, in <module>
main()
File "D:\my_stuff\Google Drive\documents\SCHOOL\Programming\Python\Programming Class\integration.py", line 8, in main
result = integral(f, n, a, b)
File "D:\my_stuff\Google Drive\Modules\nums.py", line 142, in integral
num += eval(function)
TypeError: unsupported operand type(s) for +=: 'int' and 'str'
In addition, integral by itself (in Python 3.3) works fine:
>>> from nums import integral
>>> integral('x**2')
333833.4999999991
Because of that, I believe the fault is in my program for my class... Any and all help is appreciated. Thanks :)
The issue you're running into is that input works differently in Python 2 and Python 3. In Python 3, the input function works like the raw_input does in Python 2. Python 2's input function is equivalent to eval(input()) in Python 3.
You're getting into trouble because of the quoteation marks you're typing with the formula. When you type 'x**2' (with the quotes) as your formula when running on Python 2, the text gets evaled in the input function and you get a string with no quotation marks as the result. This works.
When you give the same string to Python 3's input function, it doesn't do an eval, so the quotation marks remain. When you later eval the formula as part of your integral calculation, you get the string x**2 (without any quotation marks) as the result, not the value of x squared. This results in an exception when you try the string to 0.
To fix this, I suggest either using just one version of Python, or putting the following code at the top of your file to get a Python 3 style input in both versions:
# ensure we have Python 3 semantics from input, even in Python 2
try:
input = raw_input
except NameError:
pass
Then just type in your formula without quotation marks and it should work correctly.

Why are libcpp.vector so slow?

I'm making a few experimentations using Cython to determine whether I should use it to speed up some parts of my Django modules.
Since I'm using a lot of strings and lists of strings, I tried this:
from libcpp.string cimport string
from libcpp.vector cimport vector
def cython_test_string():
cdef unsigned short int i = 0
cdef string s
# cdef vector[string] ls
for i in range(10000):
s.append('a')
# ls.push_back(s)
def python_test_string():
s = ''
# ls = []
for i in range(10000):
s += 'a'
# ls.append(s)
Of course, C++ strings are faster than Python objects, so we get these results (for 100 iterations):
Cython : 0.0110609531403 seconds
Python : 0.193608045578 seconds
But when we uncomment the four lines that deal with vector and list, we get this:
Cython : 2.80126094818 seconds
Python : 2.13021802902 seconds
Am I missing something, or are vectors of strings extremely slow?