I am using halirutan's code in this thread to unflatten a list. It works very well but the problem is that the Module's local function f is not deleted when the function returns the output and I consequently end up with hundreds of thousands of copies of the symbol of the form f$xxxx, which eventually crashes Mathematica. I tried other solutions from the same thread, but they don't seem to work. Is there any workaround?
Asked
Active
Viewed 1,400 times
8
3 Answers
8
The creation of an explicit function f can be completely avoided by using the 3rd argument to Function. There, you can specify what Attributes the anonymous function should have and therefore, you can enforce the same behavior as you did for f.
unflatten[l_, o_] := Module[{i = 1, l1 = Flatten[l]},
Function[Null, l1[[i++]], {Listable}][o]
]
halirutan
- 112,764
- 7
- 263
- 474
6
Here is an alternative which is a bit shorter and closer to the original, and still completely free of this leak:
unflatten[l_, o_] :=
Module[{res, f, i = 1, l1 = Flatten[l]},
Block[{f},
SetAttributes[f, Listable];
f[_] := l1[[i++]];
f[o]]]
Leonid Shifrin
- 114,335
- 15
- 329
- 420
4
You can fix that with the following change:
unflatten[l_, o_] :=
Module[{f, i = 1, l1 = Flatten[l]},
SetAttributes[f, Listable];
f[_] := l1[[i++]];
With[{res = f[o]},
Clear[f, l1];
res
]
]
rm -rf
- 88,781
- 21
- 293
- 472
-
@LeonidShifrin Thanks, I've changed it, but why do you say it won't work (it worked in my test)? Isn't the
Temporaryattribute only necessary for automatic garbage collection? If I force erase all definitions, is it not the same? – rm -rf Apr 03 '14 at 17:08 -
It's not, because then this variable is not garbage -collected -
Moduleonly garbage - collects variables with attributeTemporary. You can make a simple experiment to verify that:Module[{f},f[1] = 1; Clear[f]], and then also tryClearAll, and monitor the existing symbols inGlobal`as you do this. – Leonid Shifrin Apr 03 '14 at 17:11 -
Actually, in this case, it seems to not work, no matter whether one uses
ClearorClearAll. I am a bit puzzled. – Leonid Shifrin Apr 03 '14 at 17:20 -
3Ok, the statement
Attributes[f]=Listableis the culprit. You also have to use insteadSetAttributes[f,Listable], so that theTemporaryis preserved. – Leonid Shifrin Apr 03 '14 at 17:24 -
This code reduced the number of these extra variables by a third in a test run but the number is still huge.
SetAttributes[f,Listable], however, seem to do the trick. I feel lost and can anyone please explain what is going on? – Pisto Apr 03 '14 at 17:30 -
1@Pisto Well, what happens is that the variable is only collected by
Moduleif it has the attributeTemporaryand it has noDownValuesorSubValues(not sure aboutUpValues, andOwnValuesare fine. There are also a couple of additional more subtle conditions, but they are not important for this case) at the moment when the execution leavesModule(and of course if the return value ofModuleis not some expression containing this local symbol). Now, originally, there were 2 problems: first, the codeAttributes[f] = {Listable}removes theTemporaryattribute ... – Leonid Shifrin Apr 03 '14 at 17:35 -
2@Pisto ... This happens because it explicitly alters all set of attributes, which is one reason why this form is generally not advisable.
SetAttributesfixes that, because it only addsListableto existing ones, soTemporaryis retained. Second, we needClearat the end, to remove theDownValueswhich accumulated forfduring the execution - then we fulfill both conditions and the symbol is garbage-collected. – Leonid Shifrin Apr 03 '14 at 17:37 -
@Pisto But have a look at my
Block-based solution, I think it is a bit more elegant / higher level. It is also robust against exceptions / Aborts inside function's body, which is not an issue here but an issue in general. – Leonid Shifrin Apr 03 '14 at 17:38 -
@rm-rf Sorry for my stealing your check-mark with an aggressive marketing :) – Leonid Shifrin Apr 03 '14 at 17:47
-
@LeonidShifrin...Thanks. The
Block-based solution seems to work perfectly. Even the original code is working well now whenSetAttributes[f,Listable]is used (and even has two fewer variables) ! – Pisto Apr 03 '14 at 17:49 -
@LeonidShifrin No problem :) Also, thanks for noticing the issue with the attributes. I paid no attention to the original code! :D – rm -rf Apr 03 '14 at 18:07
-
@Pisto Actually, now that you mentioned this, it is indeed right. The subtle thing here is that such local symbols with
DownValuesare not collected only if they were referenced by some external symbols / expressions. In this case, they are not, so perhaps all this is an overkill and indeed,SetAttributesalone is sufficient. I have mentioned this also here – Leonid Shifrin Apr 03 '14 at 18:16
unflatten[l_, o_] := Module[{f, i = 1, l1 = Flatten[l]}, Attributes[f] = {Listable}; f[_] := l1[[i++]]; ll = f[o]; Clear[f]; ll]– Daniel Lichtblau Apr 03 '14 at 17:03