Joe Slater on Sun, 18 Aug 2024 09:46:06 +0200


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

Applying a function to all elements of a vector


This is long, but I thought I should attempt to address this with respect to all operators, not just the first one to give unexpected results. The user manual (p. 10) says 
PARI operations are in general quite permissive. For instance taking the exponential of a vector should not make sense. However, it frequently happens that one wants to apply a given function to all elements in a vector. This is easily done using a loop, or using the apply built-in function, but in fact PARI assumes that this is exactly what you want to do when you apply a scalar function to a vector.

I think it would be very good if  GP actually did operate on vectors as the manual suggests, but at present it seems to me that the section needs correcting. Maybe I have a poor understanding of what a "scalar function" is, but it seems to me that none of the arithmetic operators except multiplication work this way. Using the manual's example of exponentiation:

> apply(x->1^x,vector(3))
%1 = [1, 1, 1]
> apply(x->0^x,vector(3))
%2 = [1, 1, 1]
> 1^vector(3) \\ All the values of the vector get converted to t_REAL for some reason.
%3 = [1.000, 1.000, 1.000]
> 0^vector(3)
  ***   at top-level: 0^vector(3)
  ***                  ^----------
  *** _^_: domain error in gpow(0,n): n <= 0
  ***   Break loop: type 'break' to go back to GP prompt

Comparison operators generally don't work at all, returning an error, except for the equality/inequality operators, which again return a single result rather than a vector. The equality/inequality operators also operate a bit differently than the manual suggests: a vector of zeros is considered equal to zero, while the manual only says "the integer 0, a 0 polynomial or a vector with 0 entries, are all tested equal by ==":

> 0==[]
%4 = 1
> 0==[0]
%5 = 1
> 0===[0]
%6 = 0
> 3==[3]
%7 = 0
> 3!=[3]
%8 = 1
> 3<[3]
***   at top-level: 3<[3]
***                  ^----
*** _<_: forbidden comparison t_INT , t_VEC (1 elts).

Logical operators seem to treat a vector as a single entity rather than a collection of objects. They also treat both an empty vector and a vector of zeros equivalently:

> 4 && [1,2,3]
%9 = 1
> [1,2,3] && 4
%10 = 1
> 4 && []
%11 = 0
> 4 && [0,0,0]
%12 = 0

Bit shift operators work for a vector on the left, but not the right, returning an error message:

> [1,2,3]<<2
%13 = [4, 8, 12]
> 2<<[1,2,3]
  ***   this should be a small integer: 2<<[1,2,3]
  ***                                      ^-------
A similar error is returned for exponentiation:

> [1,2,3]!
  ***   this should be a small integer: [1,2,3]!
  ***                                   ^--------
 
Postifx ++ and -- don't work at all, returning an error message:

> x=3
%14 = 3
> x++
%15 = 4
> x
%16= 4
> x=[3]
%17 = [3]
> x++
  ***   at top-level: x++
  ***                 ^---
  *** _++: forbidden addition t_INT + t_VEC (1 elts).

I'm not sure what's happening with the postfix ' derivative. GP seems to derive second and later terms with respect to the main value of the first term, but it's certainly not applying the derivative operator to each term entirely individually. The same applies to deriv() itself, incidentally, and I would argue that operating "componentwise" would mean taking the derivative of each element with respect to its main variable. In any event, it does not operate in the way a loop or apply() would:

> apply(x->x', [a^2,b^3,a^4])
%18 = [2*a, 3*b^2, 4*a^3]
> [a^2,b^3,a^4]'
%19 = [2*a, 0, 4*a^3]

There are possibly other inconsistencies.

Joe Slater