Please explain _pari_ and _pari_init_

1 view
Skip to first unread message

Jeroen Demeyer

unread,
Aug 19, 2010, 5:54:20 PM8/19/10
to sage-devel
Hello all,

I noticed some classes in Sage have a _pari_ method (which seems to be
used to convert self to a PARI GEN). But there is also _pari_init_,
which seems to be more or less the same (although, through a string).
What is the point of this? If there is any documentation about this,
feel free to point it out to me.

Jeroen.

Simon King

unread,
Aug 19, 2010, 6:59:14 PM8/19/10
to sage-devel
Hi Jeroen,
I don't know where it is in the documentation. But the general
situation for all interfaces is, AFAIK, like this:

Let "foo" be any interface such as singular, gap, pari, magma, ....
Let X be an object in Sage, and assume that you want to use foo on X.
Doing
sage: foo(X)
will result in trying to call a method X._foo_ with argument the
specified instance of the interface. If this is not implemented, the
method X._interface_ is called. You can see the source code of the
default implementation, e.g., by
sage: QQ._interface_??

In many cases, it is reasonable to cache the interface representation
of X. Hence, you would like that
sage: foo(X) is foo(X)
True

The solution is, typically, that some representation of X is created
in foo if foo(X) is called for the first time. This representation is
known in foo under the name foo(X).name(). And if caching is done
(i.e., if X._interface_is_cached() returns True) then X._foo_(foo) is
supposed to always return the same instance that was created the first
time.

But how is the representation created in the first place? That's the
job of the method X._foo_init_. It is supposed to return a string that
yields a representation of X when evaluated in foo. If X._foo_init_ is
not there, X._interface_init_ is called, which by default returns
repr(X) (which often makes sense, but of course not always).

I hope that was clear enough.

Cheers,
Simon

Jeroen Demeyer

unread,
Aug 20, 2010, 4:31:24 AM8/20/10
to sage-...@googlegroups.com
More or less, but not quite completely.
What if X._foo_ already uses caching?
Should I do something like:

class X:
def foo_representation(self):
# Existing function returning a representation of X in foo, with caching.
# This function might exist because a lot of functionality of X is
# implemented through interface foo.

def _foo_(self):
return self.foo_represenation()

def _foo_init_(self):
# Hope this is never called, because it is very inefficient!
return str(self.foo_represenation())

Jeroen Demeyer

unread,
Sep 19, 2010, 6:30:56 AM9/19/10
to sage-...@googlegroups.com
On 2010-08-20 00:59, Simon King wrote:
> But how is the representation created in the first place? That's the
> job of the method X._foo_init_. It is supposed to return a string that
> yields a representation of X when evaluated in foo. If X._foo_init_ is
> not there, X._interface_init_ is called, which by default returns
> repr(X) (which often makes sense, but of course not always).

But this does not explain why _foo_init_ should return a STRING
(clearly, this is often a bad idea).

Jeroen Demeyer

unread,
Sep 19, 2010, 6:43:23 AM9/19/10
to sage-...@googlegroups.com
It also seems that the Gp interface uses _pari_init_(), what's up with that?

Jeroen.

Mike Hansen

unread,
Sep 21, 2010, 7:55:45 PM9/21/10
to sage-...@googlegroups.com
Hello,

Here's what is going on. We have the pexpect interface to GP (which
we will refer to as gp) as well as C interface to PARI (which we will
refer to as pari).

gp:
- Defined in sage/intefaces/gp.py
- Specifies name="pari" in the constructor
(sage/interfaces/gp.py:156), which would normally make gp(foo) try to
call foo._pari_(), but there is special case code in Expect.__call__
to change this to use foo._gp_() instead.
(sage/interfaces/expect.py:1056)
- foo._gp_(gp) which is supposed to return a GpElement
- SageObject provides a default implementation of _gp_() which
calls SageObject._interface_(gp), which in turn tries to call
_pari_init_ (since gp has name="pari")
- Generally, the thing returned from the _XXX_init_ methods is a
string, but what really matters is that it is some object such that
when it's passed to the __call__ method of the interface object, it
"returns the right thing". See sage/structure/sage_object.pyx:387.
- SageObject also defines a default implementation of _gp_init_
which just calls _pari_init_. I don't think this function is run
anywhere.


pari:
- Defined in sage/libs/pari/gen.pyx
- Uses foo._pari_() which is supposed to return a PARI GEN object.
sage/libs/pari/gen.pyx:8414
- SageObject defines a default implementation of _pari_() which will
try calling pari(foo._pari_init_()).
- pari("string") will eventually call gp_read_str("string") which
should return a GEN object.

The idea behind all of the _XXX_ and _XXX_init_ methods is that _XXX_
returns the actual object whereas _XXX_init_ returns something which
is fed into the parent's __call__ method.

The reason why the PARI situation is a bit more complicated is that
anything string you return from _gp_init_ should be valid as a
_pari_init_ function. We should really name the name="pari" in the gp
Expect object so that we can remove the special case code. We should
then also just have the default implementation of _gp_init_ call
_pari_init_ so that if you just define that, it will work for both gp
and pari.

Sorry it took so long to answer this.

--Mike

Reply all
Reply to author
Forward
0 new messages