2
$\begingroup$

Consider some tables and function func:

phivals=RandomReal[{-Pi,Pi},10^5];
func[phi_]=phi^5*Exp[-phi];
acc=Table[0,10^5];

I would like to assign the new value to the ith element of acc depending on some condition on ith element of phivals. This is my code:

accnew = Hold@Compile[{{phivals, _Real, 1}}, Module[{val}, Do[
       val = func[Compile`GetElement[phivals, i]];
       acc[[i]] = Boole[0.1 < val < 1], {i, 1, Length[phivals], 1}]], 
     CompilationTarget -> "C", RuntimeOptions -> "Speed"] /. 
   DownValues@func // ReleaseHold

The code is very slow:

accnew[phivals]//AbsoluteTiming

{2.84727,Null}

It is probably related to the fact that acc is not among the arguments of the compiled function. However, I cannot add it:

Compile::argset: The assignment to acc is illegal; it is not valid to assign a value to an argument.

Could you please tell me how to avoid this issue and speedup the code?

$\endgroup$
2
  • 1
    $\begingroup$ It's really annoying, but CompiledFunctions don't allow to pass arguments by reference; hence one cannot efficiently modify an existing array. On has to pass in by value, make a copy and then modify the copy. Otherwise, you will have calls to MainEvaluate in the code shown by CompiledFunctionTools`CompilePrint[accnew]. This indicates a communication overhead that typically defeats the purpose of compileing with Compile. $\endgroup$ Commented Mar 5, 2023 at 16:09
  • 1
    $\begingroup$ So in order to enable true call by reference, one has to set up a LibraryLink function. That's typically quite verbose and one has to write plain C code for that... $\endgroup$ Commented Mar 5, 2023 at 16:11

1 Answer 1

3
$\begingroup$

Not sure if this is a toy example, but here's a way:

accnew2 = Hold@Compile[{{phivals, _Real, 1}}, Module[{val},
       Table[val = func[Compile`GetElement[phivals, i]];
        Boole[0.1 < val < 1], {i, 1, Length[phivals], 1}]], 
      CompilationTarget -> "C", RuntimeOptions -> "Speed"] /. 
    DownValues@func // ReleaseHold;

foo = Table[0, 10^5];

foo = accnew2[phivals]; // AbsoluteTiming
(*  {0.001453, Null}  *)

foo == acc
(*  True  *)

Alternatively:

murf = (1 - UnitStep[0.1 - #]) (1 - UnitStep[# - 1.]) &@
    func[phivals]; // AbsoluteTiming
(*  {0.000474, Null}  *)

murf == acc
(*  True  *)
$\endgroup$

Your Answer

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

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