# Compiling simple parallel function gives inconsistent results and errors

Im trying to compile the following function:

n := 5

fc = Compile[{{l,_Integer,1}},
a=1;b=1;
Do[
If[l[[i]]==1,
a=a+2b; b=b+i,
b=a+b;  a=a+i],
{i,n}];
b,
RuntimeAttributes -> {Listable},
Parallelization -> True]

fc[Tuples[{0,1},n]]


However this gives the following errors:

CompiledFunction::pext: Instruction 1 in CompiledFunction[{10,11.2,5852},{{_Integer,1}},{{2,1,0},{2,0,1}},{{0,{2,0,2}},<<1>>,{1,{<<1>>}}},<<1>>,{{46,Function[{l},a=1],2,1,0,6,0,17},{46,Function[{l},b=1],2,1,0,6,0,17},{46,Function[{l},n],2,1,0,3,0,2},{40,50,3,0,2,2,0,1},<<10>>,{4,3,1,-8},{46,Function[{l},b],2,1,0,2,0,1},{1}},Function[{l},a=1;b=1;Do[If[l[[i]]==1,a=Plus[<<2>>];b=Plus[<<2>>],b=Plus[<<2>>];a=Plus[<<2>>]],{i,n}];b,Listable],Evaluate] calls ordinary code that can be evaluated on only one thread at a time.

and

CompiledFunction::cflist: Nontensor object generated; proceeding with uncompiled evaluation.

Additionally, the result is often wrong and inconsistent. It works correctly when Parallelization is turned off. Am I doing something wrong here or is there just something wrong with my setup?

If you CompilePrint your compiled function, you'll see lots of calls to MainEvaluate:

Needs["CompiledFunctionTools"]
CompilePrint[fc]

    1 argument
1 Boolean register
11 Integer registers
1 Tensor register
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {Listable}

T(I1)0 = A1
I5 = 0
I1 = 5
I8 = 2
I0 = 1
Result = I2

1    V17 = MainEvaluate[ Function[{l}, a = 1][ T(I1)0]]
2    V17 = MainEvaluate[ Function[{l}, b = 1][ T(I1)0]]
3    I4 = MainEvaluate[ Function[{l}, n][ T(I1)0]]
4    I6 = I5
5    goto 14
6    I7 = Part[ T(I1)0, I6]
7    B0 = I7 == I0
8    if[ !B0] goto 12
9    V17I6 = MainEvaluate[ Function[{l, iCompile$$9}, Block[{i = iCompile9}, {a = a + 2 b, i}]][ T(I1)0, I6]] 10 V17I6 = MainEvaluate[ Function[{l, iCompile10}, Block[{i = iCompile10}, {b = b + i, i}]][ T(I1)0, I6]] 11 goto 14 12 V17I6 = MainEvaluate[ Function[{l, iCompile11}, Block[{i = iCompile11}, {b = a + b, i}]][ T(I1)0, I6]] 13 V17I6 = MainEvaluate[ Function[{l, iCompile12}, Block[{i = iCompile$$12}, {a = a + i, i}]][ T(I1)0, I6]]
14   if[ ++ I6 <= I4] goto 6
15   I2 = MainEvaluate[ Function[{l}, b][ T(I1)0]]
16   Return


To avoid these calls to MainEvaluate, you should modularize the variables a and b. Also, the global variable n needs to have a value. So:

Clear[fc]
fc[n_] := Compile[{{l,_Integer,1}},
Module[{a=1, b=1},
Do[
If[l[[i]]==1,
a = a + 2b; b = b + i,
b = a + b; a = a + i
],
{i,n}
];
b
],
RuntimeAttributes->{Listable},
Parallelization->True
];


Now, fc[n] has no calls to MainEvaluate:

n := 5;
CompilePrint[fc[n]]

    1 argument
1 Boolean register
10 Integer registers
1 Tensor register
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {Listable}

T(I1)0 = A1
I3 = 0
I1 = 5
I6 = 2
I0 = 1
Result = I4

1   I2 = I0
2   I4 = I0
3   I7 = I1
4   I5 = I3
5   goto 19
6   I8 = Part[ T(I1)0, I5]
7   B0 = I8 == I0
8   if[ !B0] goto 15
9   I8 = I6 * I4
10  I9 = I2 + I8
11  I2 = I9
12  I9 = I4 + I5
13  I4 = I9
14  goto 19
15  I9 = I2 + I4
16  I4 = I9
17  I9 = I2 + I5
18  I2 = I9
19  if[ ++ I5 <= I7] goto 6
20  Return


Check:

fc[n][Tuples[{0,1},n]]


{26, 20, 35, 17, 35, 24, 37, 16, 32, 24, 43, 19, 39, 26, 39, 16, 30, 23, 42, 19, 42, 28, 43, 17, 35, 26, 47, 20, 41, 27, 40, 16}

• Thanks! I didn't know about CompilePrint`, that's very useful. – Wessel de Weijer Oct 31 '19 at 15:55