6
$\begingroup$

For one of my programs I need to preallocate a multidimensional list/array. For performance reasons I want to do this within Compile and compile my program to C-code.

Now I made the following observation for the following minimal working example:

cf = Compile[{}, Block[{list},
    list = Table[{0., 1.}, {1}, {1}];
    list[[1, 1, 2]]], CompilationTarget :> "MVM"];

with CompilationTarget :> "MVM" this function works just fine. When I call cf[] I obtain the expected result 1.. Now if I change CompilationTarget->"C", I receive the following error message when I define the function cf in MMA

CCompilerDriver`CreateLibrary::cmperr: Compile error: C:\Users\AppData\Roaming\Mathematica\ApplicationData\CCompilerDriver\BuildFolder\compiledFunction100.c(152) : error C2440: 'function' : cannot convert from 'mreal' to 'MTensor *' >>
Compile::nogen: A library could not be generated from the compiled function. >>

Note that for both CompilationTargets CompilePrint shows that the code just compiles nicely.

If I keep the code to be compiled to C but change the dimensionality of the list the error message disappears

(*Compiled function*)
cf = Compile[{}, Block[{list},
    list = Table[{0., 1.}, {1}];
    list[[1, 1]]], CompilationTarget :> "C"];

Any clue how this behaviour comes about? I guess the C-compiler cannot handle these kind of Tables where I give a List of rank 1 as a first argument and only accepts arguments of rank 0. However, since the error message only appears when I define the function but not when I call it, is it safe to use anyway? (since CompilePrint shows no call to MainEvaluate).

$\endgroup$
  • 1
    $\begingroup$ I would do something like cf= With[{list =Table[{0.,1.},{1},{1}]}, Compile[{}, list[[1,1,2]],CompilationTarget:>"C"]] $\endgroup$ – Rolf Mertig Nov 23 '18 at 10:03
  • 1
    $\begingroup$ This behavior exists since v8.0, not sure if this should be called a bug or a limitation, but I think it's worth reporting to WRI. $\endgroup$ – xzczd Nov 23 '18 at 12:18
  • $\begingroup$ @MichaelE2: In your code you missed the third argument of list, i.e. when going down to the single element e.g. by list[[1,1,2]]. With list[[1,1]] everything works just fine I agree. $\endgroup$ – Display Name Nov 23 '18 at 14:07
  • $\begingroup$ No problem. I think it is not a major issue, since some easy workaround exists. It was more an observation by myself which I wanted to share. And interesting that it seemed to work with older versions of MMA. $\endgroup$ – Display Name Nov 23 '18 at 14:10
  • $\begingroup$ Note if integers are used, I get no error but the kernel crashes on execution of cf[]: cf = Compile[{}, Block[{list}, list = Table[{0, 1}, {1}, {1}]; list[[1, 1, 2]]], CompilationTarget :> "C"] $\endgroup$ – Michael E2 Nov 23 '18 at 14:12
4
$\begingroup$

…since the error message only appears when I define the function but not when I call it, is it safe to use anyway?

This depends on how you define safe. A CompiledFunction that's compiled to C succesfully owns a LibraryFunction as its last argument:

Compile[{}, 1, CompilationTarget -> C] // InputForm

CompiledFunction[……,LibraryFunction[……]]

This is what makes the CompiledFunction faster (in some cases). So, the cf will still give you the correct output, but it loses the blessing of C.

Finally, a possible workaround:

cffixed = Unevaluated@Compile[{}, Block[{list = {{{}}}}, list = Table[{0., 1.}, {1}, {1}];
     list[[1, 1, 2]]], CompilationTarget -> C] /. Part -> Compile`GetElement

The keypoint is list = {{{}}} i.e. initializing list with an empty list with correct dimension. Part -> Compile`GetElement isn't necessary but it speeds up the code.

$\endgroup$
  • $\begingroup$ Thank you for your extensive answer. I also like @Rolf Mertig 's comment. $\endgroup$ – Display Name Nov 23 '18 at 14:12
  • 1
    $\begingroup$ @DisplayName To get an array of integers, you need to be explicit about the type in the dummy initialization of list: Compile[{}, Block[{list = {{{0}}}}, list = Table[{0, 1}, {1}, {1}]; list[[1, 1, 2]]], CompilationTarget -> "C"] -- By default, the type of the empty list will be assumed to be depth-3 array of type Real. Similar type-inferencing problems are discussed here: (845), (43580) $\endgroup$ – Michael E2 Nov 23 '18 at 14:25
  • $\begingroup$ Good to know, thank you! $\endgroup$ – Display Name Nov 23 '18 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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