2

Alright, so a couple days ago I decided to try and write a primitive wrapper for the PARI library. Ever since then I've been playing with ctypes library in loading the dll and accessing the functions contained using code similar to the following:

from ctypes import *
libcyg=CDLL("<path/cygwin1.dll") #It needs cygwin to be loaded. Not sure why.
pari=CDLL("<path>/libpari-gmp-2.4.dll")

print pari.fibo #fibonacci function
#prints something like "<_FuncPtr object at 0x00BA5828>"

So the functions are there and they can potentially be accessed, but I always receive an access violation no matter what I try. For example:

pari.fibo(5) #access violation
pari.fibo(c_int(5)) #access violation

pari.fibo.argtypes = [c_long] #setting arguments manually
pari.fibo.restype = long #set the return type

pari.fibo(byref(c_int(5))) #access violation reading 0x04 consistently

and any variation on that, including setting argtypes to receive pointers.

The Pari .dll is written in C and the fibonacci function's syntax within the library is GEN fibo(long x).

Could it be the return type that's causing these errors, as it is not a standard int or long but a GEN type, which is unique to the PARI library? Any help would be appreciated. If anyone is able to successfully load the library and use ANY function from within python, please tell; I've been at this for hours now.

EDIT: Seems as though I was simply forgetting to initialize the library. After a quick pari.pari_init(4000000,500000) it stopped erroring. Now my problem lies in the in the fact that it returns a GEN object; which is fine, but whenever I try to reference the address to which it points, it's always 33554435, which I presume is still an address. I'm trying further commands and I'll update if I succeed in getting the correct value of something.

Community
  • 1
  • 1
  • I would think GEN could be one problem, as it's apparently a "pointer to long". But returning a pointer requires something pointed to, and in this case I can't tell what it is or who allocated it. Other thoughts are the fact that this is related to cygwin, or that you are on a 64-bit machine and something here is expecting 32-bit. – Peter Hansen Mar 27 '10 at 01:31
  • On my machine (Windows 7, 32-bit, Python 2.6.5) I can't even load the libpari DLL. My session locks up on the CDLL() call. Doesn't a cygwin-based package have to run from inside a cygwin session? I'm certainly not using a cygwin build of Python... – Peter Hansen Mar 27 '10 at 01:50
  • I'm running on Windows XP SP2 32-bit with Python 2.6.2, although it loads in both 2.6.4 and 2.5.1. My friend had the exact problem loading libpari; he ran his code in debug mode and it loaded successfully. –  Mar 27 '10 at 03:39
  • @silinter: fixed 2nd link again. Also upvoted both your questions. I forget how much rep you need to add >1 link but maybe this will help. :) (Also tried same thing on a Win XP machine here and it still locks up for me. Sorry I can't help more.) – Peter Hansen Mar 27 '10 at 11:41
  • Thanks for that. I'll keep trying; I think I'm simply missing some ctypes command to properly pass/receive arguments to .dll's. I'll read the PARI lib's documents properly and continue on when I know more of what PARI is doing. –  Mar 27 '10 at 15:49
  • @silinter, if, as you say in your response to Mark's answer, it's "absolutely perfect", you ought to upvote his answer and accept it (two separate actions). That's how reputation gets spread around and how this site keeps working. – Peter Hansen Jul 26 '10 at 04:18

1 Answers1

3

You have two problems here, one give fibo the correct return type and two convert the GEN return type to the value you are looking for.

Poking around the source code a bit, you'll find that GEN is defined as a pointer to a long. Also, at looks like the library provides some converting/printing GENs. I focused in on GENtostr since it would probably be safer for all the pari functions.

import cytpes
pari = ctypes.CDLL("./libpari.so.2.3.5") #I did this under linux
pari.fibo.restype = ctypes.POINTER(ctypes.c_long)
pari.GENtostr.restype = ctypes.POINTER(ctypes.c_char)    
pari.pari_init(4000000,500000)
x = pari.fibo(100)
y = pari.GENtostr(x)
ctypes.string_at(y)

Results in:

'354224848179261915075'
Mark
  • 106,305
  • 20
  • 172
  • 230
  • Whoa, that is absolutely perfect. I did figure out eventually that I'd need to set the return type to a POINTER, but I guess I didn't know ctypes (or the pari c lib :( ) to well enough to properly receive the result; it kept returning a pointer, and when I deref'd it, I always had to check the memory address around 8 bytes AFTER the address to which it pointed. Thanks a ton. Additionally, would you happen to know any good reference for relevant ctypes calls? Or would the general tutorial/ctypes reference do? –  Mar 28 '10 at 03:37
  • 1
    @silinter, the standard ctypes docs are pretty thorough, http://docs.python.org/library/ctypes.html. Also the SciPy docs talk about using it with Numpy, probably right up your alley: http://www.scipy.org/Cookbook/Ctypes – Mark Mar 28 '10 at 14:09