6

I have been playing a bit with the undocumented function

Experimental`CreateNumericalFunction

and I wanted to know if somebody found a way to make generated numerical functions listable.

Here is an example: I define two functions, f and fC

In[1]:=f = Experimental`CreateNumericalFunction[{x}, x^2, {}, {_Real},WorkingPrecision -> 30];

In[2]:=fC = Compile[{{x, _Real}}, x^2, RuntimeAttributes -> {Listable}];

The first function is not listable, while the second is:

In[3]:=f@Table[i, {i, 1, 10}]
Out[3]:=Experimental`NumericalFunction[{x}, x^2,"-NumericalFunctionData-"][{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}]

In[4]:=fC@Table[i, {i, 1, 10}]
Out[4]:={1., 4., 9., 16., 25., 36., 49., 64., 81., 100.}

Is there a way to make f also listable?

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
user12588
  • 585
  • 3
  • 8
  • What even is Experimental`CreateNumericalFunction? – QuantumDot Oct 05 '19 at 04:12
  • 1
    Unless I am mistaken, Experimental`CreateNumericalFunction is the closest one can get to compiling a function with arbitrary precision. As far as I can tell, Compile for now only takes Real64 arguments... Something like Real128 is still not available (not sure it will ever be). – user12588 Oct 05 '19 at 04:20
  • 2
    Strongly related: "[How to work with Experimental`NumericalFunction?](https://mathematica.stackexchange.com/q/43513/280)." – Alexey Popkov Oct 06 '19 at 12:44
  • One could always wrap it with a Listable function: fL = Function[x, f[x], Listable] – Michael E2 Oct 06 '19 at 12:52

1 Answers1

8

I do not know a way to make Experimental`NumericalFunction listable itself, but depending of your goals you can achieve the same behavior in several ways.

The simplest way is to create a proxy Symbol with Listable attribute:

ClearAll[f, fL]
SetAttributes[fL, Listable]
fL[x_] := f[x]
f = Experimental`CreateNumericalFunction[{x}, x^2, {}, {_}, WorkingPrecision -> 30];
fL@Table[i, {i, 1, 10}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}

It is also possible to assign the Listable attribute directly to f:

ClearAll[f]
SetAttributes[f, Listable]
f[x_] = Block[{x},
  Experimental`CreateNumericalFunction[{x}, x^2, {}, {_Real}, WorkingPrecision -> 30][x]]
f@Table[i, {i, 1, 10}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}

Instead of the attribute one can program listability via Map what can be even faster:

ClearAll[f]
f[l_List] := f /@ l;
f[x_] = Block[{x},
   Experimental`CreateNumericalFunction[{x}, x^2, {}, {_Real}, WorkingPrecision -> 30][x]];
f@Table[i, {i, 1, 10}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}

Another way is to create a listable pure function:

ClearAll[f]
f = With[{f = Experimental`CreateNumericalFunction[{x}, x^2, {}, {_Real}, WorkingPrecision -> 30]},
         Function[x, f[x], Listable]];
f@Table[i, {i, 1, 10}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}

Or you can Map f at level -1 (assuming that your input matrix contains only numbers and not expressions):

ClearAll[f]
f = Experimental`CreateNumericalFunction[{x}, x^2, {}, {_Real}, WorkingPrecision -> 30];
table = Table[i, {i, 1, 10}];
Map[f, table, {-1}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}

Also it is possible to create a numerical function accepting a list of fixed length (but probably it isn't sufficient for you):

ClearAll[f]
f = Experimental`CreateNumericalFunction[{{x, {10}}}, x^2, {10}, WorkingPrecision -> 30];
f@Table[i, {i, 1, 10}]
{1.`30., 4.`30., 9.`30., 16.`30., 25.`30., 36.`30., 49.`30., 64.`30., 81.`30., 100.`30.}
Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368