Why won't this compiled function be inlined?

Replacing the use of a pure function with a more procedural approach seems to solve that problem (here I replaced * with Times for better clarity):

dBeta12 = 
  Compile[{{k, _Integer}, {x, _Real}, {alpha, _Real}, {beta, _Real}},
   Module[{range},
    range = Range[0, k - 1];
    Total[
     Times[
      (-1)^range,
      Binomial[k - 1, range],
      prod1c[alpha, k - 1 - range],
      prod1c[beta, range],
      x^(alpha - k + range),
      (1 - x)^(beta - range - 1)
      ]
     ]
    ],
   {
    {Binomial[_, _], _Integer, 1},
    {prod1c[_, _], _Integer, 1},
    {Range[_, _], _Integer, 1}
    },
   RuntimeAttributes -> {Listable},
   Parallelization -> True,
   CompilationOptions -> {
     "InlineExternalDefinitions" -> True,
     "InlineCompiledFunctions" -> True
     }
   ];

CompilePrint[dBeta12]

gives

During evaluation of In[25]:= Compile::cfinll: The CompiledFunction CompiledFunction[{10,11.1,5852},{_Real,_Integer},{{3,0,0},{2,0,0},{3,0,3}},{<<1>>},<<1>>,{{6,0,6},{6,4,1},{35,6,2,1},{6,4,3},{3,2},{36,1,3,2,1},{4,3,6,-1},{40,43,2,1,1,2,1,2},{41,257,3,0,0,2,1,2,3,1,1},<<1>>,{33,1,3},{6,4,5},{3,4},{37,1,5,3,2},{16,3,2,4},{7,4,3},{4,5,3,-3},{1}},Function[{value,count},Times@@(value-Range[count]),Listable],Evaluate] could not be inlined because its use requires threading with the Listable runtime attribute.

During evaluation of In[25]:= Compile::cfinll: The CompiledFunction CompiledFunction[{10,11.1,5852},{_Real,_Integer},{{3,0,0},{2,0,0},{3,0,3}},{<<1>>},<<1>>,{{6,0,6},{6,4,1},{35,6,2,1},{6,4,3},{3,2},{36,1,3,2,1},{4,3,6,-1},{40,43,2,1,1,2,1,2},{41,257,3,0,0,2,1,2,3,1,1},<<1>>,{33,1,3},{6,4,5},{3,4},{37,1,5,3,2},{16,3,2,4},{7,4,3},{4,5,3,-3},{1}},Function[{value,count},Times@@(value-Range[count]),Listable],Evaluate] could not be inlined because its use requires threading with the Listable runtime attribute.

Out[26]= "
        4 arguments
        11 Integer registers
        5 Real registers
        9 Tensor registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {Listable}

        I0 = A1
        R0 = A2
        R1 = A3
        R2 = A4
        I1 = 0
        I2 = -1
        I10 = 12
        I5 = 1
        I9 = 3
        Result = R4

1   I4 = I0 + I2
2   I6 = I1
3   I7 = Subtract[ I4, I2]
4   T(I1)0 = Table[ I7]
5   I8 = I2
6   goto 8
7   Element[ T(I1)0, I6] = I8
8   if[ ++ I8 <= I4] goto 7
9   T(I1)1 = Power[ I2, T(I1)0]
10  I3 = I0 + I2
11  T(I1)2 = MainEvaluate[ Hold[Binomial][ I3, T(I1)0]]
12  T(I1)3 = - T(I1)0
13  I6 = I0 + I2
14  T(I1)4 = I6 + T(I1)3
15  T(R1)3 = CompiledFunctionCall[ Hold[CompiledFunction[{value, \
count}, Times @@ (value - Range[count]), -CompiledCode-]][ R1, T(I1)4]]
16  T(R1)4 = CompiledFunctionCall[ Hold[CompiledFunction[{value, \
count}, Times @@ (value - Range[count]), -CompiledCode-]][ R2, T(I1)0]]
17  I3 = - I0
18  R3 = R1 + I3
19  T(R1)5 = R3 + T(I1)0
20  T(R1)6 = Power[ R0, T(R1)5]
21  R3 = - R0
22  R4 = I5
23  R4 = R4 + R3
24  T(I1)5 = - T(I1)0
25  R3 = R2 + I2
26  T(R1)7 = R3 + T(I1)5
27  T(R1)5 = Power[ R4, T(R1)7]
28  T(R1)7 = CoerceTensor[ I9, T(I1)1]]
29  T(R1)8 = CoerceTensor[ I9, T(I1)2]]
30  T(R1)7 = T(R1)7 * T(R1)8 * T(R1)3 * T(R1)4 * T(R1)6 * T(R1)5
31  R4 = TotalAll[ T(R1)7, I10]]
32  Return
"

So the execution of prod1c does not now require a MainEvaluate call, but another warning tells us that the inlining still did not work.

Looking for what causes this warning I got down to the following minimal not working example producing the same warning:

fc1 = Compile[{{k, _Integer}},
   Times[k],
   RuntimeAttributes -> {Listable}
   ];
fc2 = Compile[{{k, _Integer}},
   fc1[Range[k]],
   CompilationOptions -> {
     "InlineExternalDefinitions" -> True,
     "InlineCompiledFunctions" -> True
     }
   ];

CompilePrint@fc2

So it seems that inlining does not like listable compiled functions. In this MNWE the fix is therefore trivial:

fc1 = Compile[{{k, _Integer, 1}},
   Times[k]
   ];
fc2 = Compile[{{k, _Integer}},
   fc1[Range[k]],
   CompilationOptions -> {
     "InlineExternalDefinitions" -> True,
     "InlineCompiledFunctions" -> True
     }
   ];

CompilePrint@fc2

which compiles and inlines fine.

Doing the same with your actual function we finally get:

prod1c = Compile[{{value, _Real}, {count, _Integer, 1}},
   Apply[Times, value - Range[count]],
   Parallelization -> True
   ];

dBeta12 = 
  Compile[{{k, _Integer}, {x, _Real}, {alpha, _Real}, {beta, _Real}},
   Module[{range},
    range = Range[0, k - 1];
    Total[
     Times[
      (-1)^range,
      Binomial[k - 1, range],
      prod1c[alpha, k - 1 - range],
      prod1c[beta, range],
      x^(alpha - k + range),
      (1 - x)^(beta - range - 1)
      ]
     ]
    ],
   {
    {Binomial[_, _], _Integer, 1},
    {prod1c[_, _], _Integer, 1},
    {Range[_, _], _Integer, 1}
    },
   RuntimeAttributes -> {Listable},
   Parallelization -> True,
   CompilationOptions -> {
     "InlineExternalDefinitions" -> True,
     "InlineCompiledFunctions" -> True
     }
   ];

CompilePrint[dBeta12]

Which seems to compile and inline without problems. I cannot test if the result is what you would expect though. Also, I'm not sure why the pure function poses a problem here.


The option "InlineCompiledFunctions" is notoriously unreliable for reasons I cannot recall. You can get it working with With, though.

Clear[prod1c, dBeta12];
prod1c = Compile[{{value, _Real}, {count, _Integer}},
   Apply[Times, value - Range[count]]
   ];

dBeta12 = With[{cf = prod1c},
   Compile[{{k, _Integer}, {x, _Real}, {alpha, _Real}, {beta, _Real}},
     Total[(-1)^#*Binomial[k - 1, #]*cf[alpha, k - 1 - #]*cf[beta, #]*
        x^(alpha - k + #)*(1 - x)^(beta - # - 1) &[Range[0, k - 1]]
     ],
    RuntimeAttributes -> {Listable},
    Parallelization -> True,
    CompilationOptions -> {
      "InlineExternalDefinitions" -> True,
      "InlineCompiledFunctions" -> True}
    ]
   ];

As Binomial is not a CompiledFunction, it cannot be inlined. But you may write your own compiled version...

Edit: In the meantime, I found the source of this idea here.