Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Pass by reference for compiled functions

184 views
Skip to first unread message

Eric Michielssen

unread,
Nov 29, 2010, 6:10:19 AM11/29/10
to
For noncompiled functions, one can pass arguments "by reference" and then
modify them inside the routine by assigning the function the attribute
HoldAll.

This does not work for compiled functions: it does not appear possible to
modify arguments to compiled functions, even if they are passed as "global
variables". That is, Mathematica responds to

Myfunction = Compile[
{{var1,_Real}},
Module[{},
Modify var 1 or var2;
Return[]], {var2,_Real}];

With

Compile::argset: The assignment to var1 is illegal; it is not valid to
assign a value to an argument. >> And something similar for var2.

HoldAll does not seem to apply here...

This makes it memory-inefficient to modify large arrays in compiled
functions, as one would have to operate on a copy of the array.

Is there a workaround in Mathematica 8?

Eric Michielssen

Oliver Ruebenkoenig

unread,
Nov 30, 2010, 4:06:16 AM11/30/10
to

a workaround could be to use LibraryFunctionLoad and use the "Shared"
attribute.

Oliver

>
> Eric Michielssen
>
>
>
>

Daniel Lichtblau

unread,
Nov 30, 2010, 4:01:33 AM11/30/10
to
Eric Michielssen wrote:
> For noncompiled functions, one can pass arguments "by reference" and then
> modify them inside the routine by assigning the function the attribute
> HoldAll.
>
> This does not work for compiled functions: it does not appear possible to
> modify arguments to compiled functions, even if they are passed as "global
> variables". That is, Mathematica responds to
>
> Myfunction = Compile[
> {{var1,_Real}},
> Module[{},
> Modify var 1 or var2;
> Return[]], {var2,_Real}];
>
> With
>
> Compile::argset: The assignment to var1 is illegal; it is not valid to
> assign a value to an argument. >> And something similar for var2.
>
> HoldAll does not seem to apply here...
>
> This makes it memory-inefficient to modify large arrays in compiled
> functions, as one would have to operate on a copy of the array.
>
> Is there a workaround in Mathematica 8?
>
> Eric Michielssen

Not to my knowledge. I agree this mutability would be a really nice
capability to have. I have wanted it myself since almost forever. Well,
at least since the time I posted the message at the URL below.

http://forums.wolfram.com/mathgroup/archive/2001/Feb/msg00195.html

We have discussed the desire for call-by-reference, or something else
that might allow for mutability of arrays, within Compile. People here
seem toa gree it could be very useful. But I do not know whether we will
attempt to go in this direction, or what might be the design or
implementation issues (I suspect neither is trivial).

One thing that might be new to version 8 is an ability to pass large
arrays in Compile and not have them automatically copied. It is only
when one needs to alter them that a copy is needed. So it is possible to
invoke what amount to subroutines (that is, Compile calling functions
that are also defined via Compile), using parge arrays as arguments, and
not suffering a time or memory penalty. But again, this only holds if
the arrays are not to be modified. I'm told some code along these lines
might appear in an upcoming Wolfram blog.


Daniel Lichtbau
Wolfram Research

Leonid Shifrin

unread,
Dec 1, 2010, 2:09:22 AM12/1/10
to
Hi Eric,

You can also kind of emulate pass-by-reference by inlining compiled
functions, but this will only
work if your caller function is also Compiled, and all the ingredients are
compiled. Here is an example:

Clear[primeQ ];
primeQ =
Compile[{{n, _Integer}},
Total[1 - Unitize@Mod[n, Range[2, IntegerPart[Sqrt[n]] + 1]]] ==
0];

ClearAll[primes];
primes =
Compile[{},
list = Select[list, primeQ],
CompilationOptions -> {"InlineExternalDefinitions" -> True,
"InlineCompiledFunctions" -> True}];

test =
Compile[{},
Module[{list = Range[100000]},
primes[];
list],
CompilationOptions -> {"InlineExternalDefinitions" -> True,
"InlineCompiledFunctions" -> True}];


In[87]:=
test[]//Short//Timing
Out[87]=
{0.828,{1,3,5,7,11,13,17,19,23,29,31,<<9570>>,99871,99877,99881,99901,99907,99923,99929,99961,99971,99989,99991}}

Note that the variable <list> has not been defined in <primes>, so <primes>
works essentially
like a macro. At the end, everything is inlined inside <test>, and for this
to work, this must
have happened before the variables are bound. So, we actually do change the
variable <list>
defined in <test>, even though it is done inside <primes>. At the same time,
the global <list>
does not acquire any value. But this would not work if <primes> would not
have entirely compiled -
for instance, if you change primeQ (compiled) to PrimeQ (uncompiled,
built-in, external call).

You can inspect the final compiled code for <test> by calling test[[6]] and
see that it indeed
did compile completely to byte-code. In particular, you should be able to
compile to C if needed.
So, this is not the true pass-by-reference since no arguments are passed
explicitly, but this seems
to give similar means of combining larger programs from smaller pieces
without copying data, more
like templates. I am not sure about the status of this "technique", I just
discovered it recently - this
looks more like a hack to me, but it seems to work.

Hope this helps.

Regards,
Leonid


On Mon, Nov 29, 2010 at 2:10 PM, Eric Michielssen
<emic...@eecs.umich.edu>wrote:

0 new messages