Karim Belabas on Tue, 16 Jul 2019 13:25:21 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: Using local variable for memoizing in recursion


* Дмитрий Рыбас [2019-07-16 09:44]:
> So, for system functions pointers are marked with ampersand (&) and for
> user functions pointers are marked with tilde (~) in 2.12 ?

Not quite: we don't have true user function pointers (hence the tilde
instead of the customary ampersand). It's really a mutable *container*
(we're allowing to modify in place an object of list/vector/matrix-type),
this is not a side effect changing a variable value. Compare:

? f(~x) = x = 1;
? x = 0; f(~x); x    \\ x didn't change
%2 = 0

? g(~x) = x[1] = 1;
? x = [0]; g(~x); x  \\ but the *content* of a container type x would change
%4 = [1]

This can also be used to make sure that a given bulky argument is
*never* copied by user functions. GP's copy optimizer is usually clever
enough but it sometimes errs on the paranoid side to survive problematic
constructs (usually involving global variables). E.g.,
  x = [1]; /* global; no lexical scoping */
  f(y) = /*...complicated code...*/;
  f(x)

Must must we make a deep copy of 'x' in case some user subroutine called by
f messes with it, or is a shallow copy safe enough ? [ In fact it's
rarely safe because GP is not compiled: global subroutines called by f may be
redefined at any time... ]

With 
  f(~y) = ...
  f(~x)
there's no problem: no copy.

> That's great! But a little bit strange if that difference really exist.
> Will be waiting for 2.12 stable.
> 
> As for "cumbersome" way, here is what I has written:
> 
> p(n,k) =
>   {
>     local(M = Map()); /* Do not use my() here, use local() !! */
>     my(memo_p = (N,K)-> my(res);
>        if(N==0 && K==0,return(1));
>        if(k<1,return(0));
            ^--- you mean K here

>        if(mapisdefined(M,[N,K],&res),return(res));
>        if(K>=N,res=numbpart(N);mapput(M,[N,K],res);return(res));
>        res=self()(N,K-1)+self()(N-K,K);
>        mapput(M,[N,K],res);
>        return(res));
>     memo_p(n,k);
>   }

You can simplify this a little:

p(n,k) =
  {
    local(M = Map()); /* yes, local is needed: sorry... */
    my(memo_p = (N,K)-> my(res);
       if(N==0 && K==0,return(1));
       if(K<1,return(0));
       if(mapisdefined(M,[N,K],&res),return(res));
       res = if(K>=N, numbpart(N), self()(N,K-1)+self()(N-K,K));
       mapput(M,[N,K],res); return(res));
    memo_p(n,k);
  }

Cheers,

    K.B.
--
Karim Belabas, IMB (UMR 5251)  Tel: (+33) (0)5 40 00 26 17
Universite de Bordeaux         Fax: (+33) (0)5 40 00 21 23
351, cours de la Liberation    http://www.math.u-bordeaux.fr/~kbelabas/
F-33405 Talence (France)       http://pari.math.u-bordeaux.fr/  [PARI/GP]
`