Defining a function which is numerical on all vectors of arguments

There is an attribute NumericFunction in Mathematica that can do the following job:

Attributes[f] = {NumericFunction};
NumericQ[f[1,2,3,4]]


then returns true. However, the following return false

NumericQ[f[{1,2,3,4}]]; NumericQ[f[1,{2},3,{4}]]


which makes sense by Documentation on NumericFunction. However, I want to define a function $$f$$ that returns True even in above cases, how can this be achieved?

Curiously, functions like HypergeometricPFQ has Attributes NumericFunction, but NumericQ[HypergeometricPFQ[{1, Sqrt[2]}, {Pi}, 1/3]] still returns true despite having lists in its arguments, why?

My goal is to define an f such that all expressions like f[1,{2},3,{4}], 1+5*f[1,{2},3,{4}], Sin[1+5*f[1,{2},3,{4}]] returns true upon NumericQ. How can this be done?

Thank you.

Update: After much thoughts, I think I found a solution:

SetAttributes[f, NumericFunction]; Unprotect[NumericQ];
$$numericflag = 0; NumericQ[expr_] /; FreeQ[expr, f] == False &&$$numericflag == 0 :=
Block[{bool}, $$numericflag = 1; bool = NumericQ[expr /. f[x__] :> f @@ Flatten[{x}]];$$numericflag =
0; Return[bool]]; Protect[NumericQ];


it works as expected: NumericQ[Pi + 58 + f[2, 3, {4, 4}]], NumericQ[Sin[f[2,{3,{0,0}}]]] all return true.

• I don't have a rigorous answer, but it appears that it is linked to the fact f is not defined. If you define f (e.g. f[l___]:=1 the result of NumericQ@f[{1},2,3] become True May 14, 2020 at 13:21
• @youyou Isn't it because f evaluates to 1 first? NumericQ doesn't have any Hold* attributes. May 14, 2020 at 15:27

I thought @swish would incorporate my comment, but let me put it here, since it is an answer to the question. In the following, the arguments of f can be numbers or any sort of nested lists of numbers.

f /: NumericQ[f[args___]] /; VectorQ[Flatten@{args}, NumericQ] := True;

NumericQ[f[1, 2, 3, 4]]
NumericQ[f[{1, 2, 3, 4}]]
NumericQ[f[1, {2}, 3, {4}]]
NumericQ[f[x]]  (* False -- should check both cases T, F *)
NumericQ[f[]]   (* True  -- same as NumericQ[Sin[]] *)
(*
True
True
True
False
True
*)


Update

@pisco points out that the above does not work if f[..] is nested inside other numeric expressions. There is an internal function that could be used to replace NumericQ:

ClearAll[f];
Attributes@f = {NumericFunction};

InternalWouldBeNumericQ[2 + f[1, {2}, 3], {}]
(*  True  *)


The last list is a list a variables, the function tests whether f would be numeric if numeric values were substituted for the variables.

• Thank you for your answer. However, one major shortcoming seems that NumericQ[1+f[1,2,3]] returns false. If one sets NumericFunction attributes to f, this returns true. However, NumericQ[1+f[1,{2},3]] still returns false. How to tackle this? May 28, 2020 at 5:43
• @pisco I added a workaround to my answer. Feel free to unaccept if it's not satisfactory. The workings of NumericQ are hidden from Trace. I suspect there are some optimizations in C that get around my first def. May 28, 2020 at 13:16

There is a slight problem with NumericQ, that prevents one to define your UpValues with it. So that would not work as expected:

f /: NumericQ[_f] := True


But manually

UpValues[f] = {HoldPattern[NumericQ[_f]] :> True};


it works as expected:

NumericQ[f[{1, 2, 3, 4}]]
NumericQ[f[1, {2}, 3, {4}]]
(* True *)
(* True *)

• I think the solution is a little over-eager :) -- Try NumericQ[f[1, {2, t}, 4]] which should return False. I think the def. f /: NumericQ[f[args___]] /; VectorQ[Flatten@{args}, NumericQ] := True` is more on-target. May 14, 2020 at 17:33