0
$\begingroup$

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?

$\endgroup$
3
$\begingroup$

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 = iCompile$9}, {a = a + 2 b, i}]][ T(I1)0, I6]]
 10   V17I6 = MainEvaluate[ Function[{l, iCompile$10}, Block[{i = iCompile$10}, {b = b + i, i}]][ T(I1)0, I6]]
 11   goto 14
 12   V17I6 = MainEvaluate[ Function[{l, iCompile$11}, Block[{i = iCompile$11}, {b = a + b, i}]][ T(I1)0, I6]]
 13   V17I6 = MainEvaluate[ Function[{l, iCompile$12}, 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}

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

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.