hermann on Sun, 10 Sep 2023 10:45:11 +0200


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

Re: Manually transpile Python code to GP: what about class / __name__ ?


Perhaps a bit of motivation first.
RSA_numbers_repo is available in Python, nodejs/JavaScript and PARI/GP.

On 2023-09-09 20:43, Bill Allombert wrote:
What remains is transpilation of Python class RSA.
Is there a "class" concept in GP?

No, GP is not object-oriented at all. It has some minimal
functional-programming features
(anonymous functions and closure).

Thanks, what I need is that it "looks similar" to Python class code.
In order to port easily code from one language to the other.


It seems so, as "." is not a normal name character:

You know, there is a GP manual you could read...

I did of course, but searched for "class" and found many hits, but not on GP class.

Thanks, I found "2.8 Member functions":
https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.15.4/users.pdf#page=48

The preceding chapters on functions and closures helped as well.


I am happy with RSA member function "square_sums_4()".
Function comment "Example" section shows how to use.
In case mailing software scambles display, here is function on github:
https://github.com/Hermann-SW/RSA_numbers_factored/blob/main/pari/RSA_numbers_factored.gp#L1525-L1552

RSA.square_sums_4=x->{
\\  """
\\  Args:
\\      x: RSA_number length or RSA_number
\\  Returns:
\\      _: square sums of tuple elements sum up to RSA number
\\  Example:
\\  ```
\\      ? [p,q]=[13,29];
\\      ? n=p*q;
\\      ? sq4=RSA.square_sums_4([0,0,p,q]);
\\      ? sq4
\\      [15, 4, 6, 10]
\\      ? vecsum([x^2|x<-sq4])==n
\\      1
\\      ? vecsum([x^2|x<-RSA.square_sums_4(129)])==RSA.get(129)[2]
\\      1
\\      ? RSA.square_sums_4(59)
\\ [179348979911745603741332779404, 85487774497975933628103176206, 105946792191696573364448656521, 144715520252806281192691658344]
\\      ?
\\  ```
\\  """
    my(r=self.get_(x),p,q);
    assert(has_factors(r)&&r[3]%4==1&&r[4]%4==1);
    p=sq2(r[3]);
    q=sq2(r[4]);
    return([p[1]*q[1],p[2]*q[2],p[1]*q[2],p[2]*q[1]]);
}


I have few questions I was not able to resolve by reading GP manual and experiment:

1)
Is it possible to define a member function without parameter?
I cheated by using "dummy" parameter, and not passing parameter when calling:

RSA.factored_2=dummy->{
\\  """
\\  Args:
\\      _: none.
\\  Returns:
\\      _: list of RSA_number with factorization dictionaries.
\\  """
    return([r|r<-rsa,has_factors_2(r)]);
}


2)
I was not able to get the syntax right for a parameter with default value.
I used below workaround.
Is is possible to define default value for GP member function parameter directly?

factored(mod4=-1)=
{
\\  ...
    return([r[1..4]|r<-rsa,has_factors(r,mod4)]);
}
RSA.factored=factored;


3)
I did not need sofar, but is it possible to pass multiple parameter"s to GP member function? (this likely does not make sense for what GP member functions have been implemented)


I did not transpile Python "__iter__(self)" and "__next__(self)" needed for class iteration.
Not needed since GP can do that with foreach easily.

Instead of Python:
from RSA_numbers_factored import RSA
RSA=RSA()
for r in RSA:
...     print(str(r[0])+" ", end="")
...
59 79 100 110 120 129 130 140 150 155 160 170 576 180 190 640 200 210 704 220 230 232 768 240 250 260 270 896 280 290 300 309 1024 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 1536 470 480 490 500 617 2048 >>>


GP can do this way, at least on "factored()" and "factored_2()":

? readvec("RSA_numbers_factored.gp");
? {
foreach(RSA.factored(),r,
    print1(r[1]," "));
}
59 79 100 110 120 129 130 140 150 155 160 170 576 180 190 640 200 210 704 220 230 232 768 240 250
?


Regards,

Hermann.