5
$\begingroup$

Consider the following toy code:

table = Table[{i^0.11, i^0.005}, {i, 1, 1000, 0.5}];
val = Compile[{{table, _Real, 2}, {i, _Integer}}, table[[i]][[1]], CompilationOptions -> 
 "InlineCompiledFunctions" -> 
  True, CompilationTarget -> "C"]
sum = Hold@
    Compile[{{table, _Real, 2}}, 
     Sum[val[table, i], {i, 1, Length[table], 1}], CompilationOptions -> 
 "InlineCompiledFunctions" -> 
  True, CompilationTarget -> "C", Parallelization -> True] /. OwnValues@val //
   ReleaseHold

where I define compiled value val[table,i], and then compiled sum over i, sum[table]. I get error

Function::flpar: Parameter specification {table,1} in {table,1}\[Function]table[[1]][[1]] should be a symbol or a list of symbols.

Could you please tell me how to have the compile the sum over i? I need this since in realistic case table is also a (very complicated) compiled function, and I also cannot omit the intermediate definition val, as there are too many intermediate actions that I need to get in order to obtain val.

$\endgroup$

1 Answer 1

5
$\begingroup$

Inlining is really not Compile's strength. I got it working though by declaring an accumulator a and by replacing Sum by a Do loop.

table = Table[{i^0.11, i^0.005}, {i, 1, 1000, 0.5}];

val = Compile[{{table, _Real, 2}, {i, _Integer}},
   Compile`GetElement[table, i, 1],
   CompilationTarget -> "C",
   RuntimeOptions -> "Speed"
   ];

sum = With[{val = val},
   Compile[{{table, _Real, 2}},
    Block[{a},
     a = val[table, 1];
     Do[a += val[table, i], {i, 2, Length[table], 1}];
     a
     ],
    
    CompilationTarget -> "C",
    CompilationOptions -> {"InlineCompiledFunctions" -> True},
    RuntimeOptions -> "Speed"
    ]
   ];

Note however that this is very inefficient, because Compile does not really inline; when tensors are involved, it typically adds a CopyTensor for each inlined call to val -- and that's just to extract a single number from the array. That means: "InlineCompiledFunctions" -> True enforces call by value! This is really a total performance killer for Compile and the reason why I moved to directly programming in C++ via LibraryLink for complicated work flows.

If you insist on using Compile (which I would understand because that was my own practice for a long time), then I would suggest to also measure the performance of "InlineCompiledFunctions" -> False. Depending on the workload, it might be faster even though not inlined.

Edit

Just to demonstate how inefficient this is, let's compare with the manually inlined version below:

sum2 = With[{val = val}, Compile[{{table, _Real, 2}},
    Block[{a},
     a = Compile`GetElement[table, 1, 1];
     Do[a += Compile`GetElement[table, i, 1], {i, 2, Length[table],1}];
     a
     ],
    CompilationTarget -> "C",
    RuntimeOptions -> "Speed"
    ]
   ];

Here the comparison:

table = RandomReal[{-1, 1}, {100000, 10}];
result = sum[table]; // RepeatedTiming // First
result2 = sum2[table]; // RepeatedTiming // First
result == result2

0.872045

0.000093828

True

So the first version takes more than 50000(!) times longer.

$\endgroup$
4
  • $\begingroup$ Why does the code use Compile`GetElement[table, i, 1] rather than table[[i,1]] ? $\endgroup$ May 8 at 4:52
  • $\begingroup$ Does your comment about CopyTensor mean that generally, computations involving matrices are slow with Compile? I am noticing that Compile is quite slow at building a 100x100x32x32 tensor (takes a few seconds) $\endgroup$ May 8 at 4:56
  • 2
    $\begingroup$ "Why does the code use Compile`GetElement[table, i, 1] rather than table[[i,1]]?" Because Compile`GetElement skips the bound checks and is thus faster. $\endgroup$ May 8 at 5:53
  • 1
    $\begingroup$ "Does your comment about CopyTensor mean that generally, computations involving matrices are slow with Compile?" There are a few workarounds, but in general yes, writing complicated code for multidimensional arrays is often more efficient when it is done with plain C code via LibraryLink instead with Compile. $\endgroup$ May 8 at 5:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.