2

I would like to call nfroots({nf}; x) function of PARI/GP from Python. (see function no 3.13.135.on page 371 in this link:), but the probllem is, I couldn't send the algebraic expression or the polynomial, that need to be send, for example, x^2-7x+12, here is a very simple example of what gp can do with a quartic polynomial:

> V = readvec("coeff.txt");
> print(V)
[1,-7,12]
> P = Pol(V);  # I get following error when I use Pol in my code:    func=self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'pol' not found 
> print(P)
x^2 -7*x +12
> print(nfroots(,P))
>4, 3

From the answer of Stephan Schlecht (click here), I manage to write -

from ctypes import *
pari = cdll.LoadLibrary("C:\\Program Files\\Pari64-2-11-3\\libpari.dll")

pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))

pari.nfroots.restype = POINTER(POINTER(c_long))


pari.pari_init(2 ** 19, 0)

def t_vec(numbers):
    l = len(numbers) + 1
    p1 = pari.cgetg(c_long(l), c_long(10)) #t_POL    =  10,
    for i in range(1, l):
        p1[i] = pari.stoi(c_long(numbers[i - 1]))
    return p1

def main():    
    h = "x^2-7x+12"
    res = pari.nfroots(t_vec(h))  
for i in range(1, len(res)):
         print(pari.itos(res[i]))
if __name__ == '__main__':
    main()

Note that there is specific process to create of PARI objects (see the answer of Stephan Schlecht), I changed the value for t_POL = 10 , but the code didn't work, How can I execute the above PARI/GP code from python?

  • Please clarify how your code "didn't work". Your code isn't runnable without pre-existing setup, so most people cannot verify it at all. Please also see the [How to Ask help page](https://stackoverflow.com/help/how-to-ask). – MisterMiyagi Mar 23 '20 at 07:46

1 Answers1

3

One solution could be:

  • use gtopoly, return type is POINTER(c_long)
  • return type of nfroots is POINTER(POINTER(c_long))
  • output of result with .pari_printf

Code

from ctypes import *

pari = cdll.LoadLibrary("libpari.so")

pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))

(t_VEC, t_COL, t_MAT) = (17, 18, 19)  # incomplete
precision = c_long(38)

pari.pari_init(2 ** 19, 0)


def t_vec(numbers):
    l = len(numbers) + 1
    p1 = pari.cgetg(c_long(l), c_long(t_VEC))
    for i in range(1, l):
        p1[i] = pari.stoi(c_long(numbers[i - 1]))
    return p1


def main():
    V = (1, -7, 12)
    P = pari.gtopoly(t_vec(V), c_long(-1))
    res = pari.nfroots(None, P)
    pari.pari_printf(bytes("%Ps\n", "utf8"), res)


if __name__ == '__main__':
    main()

Test

If you run the program you get the desired output in the debug console:

[3, 4]

Conversions

With glength one can determine the length of a vector, see https://pari.math.u-bordeaux.fr/dochtml/html/Conversions_and_similar_elementary_functions_or_commands.html#length

With itos a long can be returned if the parameter is of type t_INT, see section 4.4.6 of https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf.

In code it would look like this:

pari.glength.restype = c_long
pari.itos.restype = c_long
... 
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
    print(pari.itos(res[i]))

To GENtostr gives a string representation of the argument. It could be used like so:

pari.GENtostr.restype = c_char_p
...
print("elements as generic strings: ")
for i in range(1, pari.glength(res) + 1):
    print(pari.GENtostr(res[i]).decode("utf-8"))

There are many more conversion options, see the two links above.

Stephan Schlecht
  • 26,556
  • 1
  • 33
  • 47
  • Thanks man! but why we don't get value from `pari.pari_printf(bytes("%Ps\n", "utf8"), res)` like `print("ellisdivisible =", y)` in previous code? Same thing happened in lift(Q) of previous answer, for lift(Q) in `pari.pari_printf(bytes("Q: %Ps\n", "utf8"), Q)`, I need to use these values in other functions, so is there a way we can get them as value which can be used and printed in python? Thanks again for your help. – Consider Non-Trivial Cases Mar 23 '20 at 11:44
  • I have added a section on conversions to the answer. – Stephan Schlecht Mar 23 '20 at 18:10
  • Fantastic!! both works, you have been most helpful, BTW how one can see If he runs the program "in the debug console", how to see in "in the debug console"? , also would you give a short procedure how to figure oit what function needs which conversion.. if you have time...Thanks again! – Consider Non-Trivial Cases Mar 23 '20 at 20:47
  • When changing from the Python world to the PARI/C world and back, conversions are required. The type of conversion depends on the function actually called and the type. A good source might be the documentation under the two links given in the answer. The debug console is nothing magic, it is my name for the view of the Python IDE that displays the output generated by the Python program. – Stephan Schlecht Mar 24 '20 at 21:01
  • Hello Stephan, I don't get the get the desired output in the debug console, like you I had to the conversion which you added later,it means `pari.pari_printf(bytes("%Ps\n", "utf8"), res)` does not work in my python, any idea why? BTW what does `pari.pari_printf(bytes("%Ps\n", "utf8"), res)` do? – Consider Non-Trivial Cases Mar 26 '20 at 17:43
  • https://stackoverflow.com/questions/60889072/fraction-value-problem-in-ctypes-to-pari-gp?noredirect=1#comment107728782_60889072 – Consider Non-Trivial Cases Mar 27 '20 at 18:26