Compile `DeleteCases`
up vote
5
down vote
favorite
How is the function DeleteCases
compilable if Compile
does not support patterns?
My question refers to this thread here where I want to use an If
statement without the third argument required. Since my output of the If
statement within compile always gives a positive real number, I'd like to get rid of the numbers which I invoke with a negative third argument in the If
statement (the third arguments seems to be necessary so that the If
statement is compiled at all).
Maybe there now might be even a better solution than this workaround provided by @Mr.Wizard but I do not really understand his suggestion (or is it meant to use DeleteCases
outside of Compile
?).
compile
add a comment |
up vote
5
down vote
favorite
How is the function DeleteCases
compilable if Compile
does not support patterns?
My question refers to this thread here where I want to use an If
statement without the third argument required. Since my output of the If
statement within compile always gives a positive real number, I'd like to get rid of the numbers which I invoke with a negative third argument in the If
statement (the third arguments seems to be necessary so that the If
statement is compiled at all).
Maybe there now might be even a better solution than this workaround provided by @Mr.Wizard but I do not really understand his suggestion (or is it meant to use DeleteCases
outside of Compile
?).
compile
6
Only a restricted set of forms is supported inCompile
. You can e.g.DeleteCases[list, 123]
. I think only literal values can be used as the second argument.
– Szabolcs
Nov 21 at 11:03
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29
add a comment |
up vote
5
down vote
favorite
up vote
5
down vote
favorite
How is the function DeleteCases
compilable if Compile
does not support patterns?
My question refers to this thread here where I want to use an If
statement without the third argument required. Since my output of the If
statement within compile always gives a positive real number, I'd like to get rid of the numbers which I invoke with a negative third argument in the If
statement (the third arguments seems to be necessary so that the If
statement is compiled at all).
Maybe there now might be even a better solution than this workaround provided by @Mr.Wizard but I do not really understand his suggestion (or is it meant to use DeleteCases
outside of Compile
?).
compile
How is the function DeleteCases
compilable if Compile
does not support patterns?
My question refers to this thread here where I want to use an If
statement without the third argument required. Since my output of the If
statement within compile always gives a positive real number, I'd like to get rid of the numbers which I invoke with a negative third argument in the If
statement (the third arguments seems to be necessary so that the If
statement is compiled at all).
Maybe there now might be even a better solution than this workaround provided by @Mr.Wizard but I do not really understand his suggestion (or is it meant to use DeleteCases
outside of Compile
?).
compile
compile
asked Nov 21 at 10:47
Display Name
51838
51838
6
Only a restricted set of forms is supported inCompile
. You can e.g.DeleteCases[list, 123]
. I think only literal values can be used as the second argument.
– Szabolcs
Nov 21 at 11:03
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29
add a comment |
6
Only a restricted set of forms is supported inCompile
. You can e.g.DeleteCases[list, 123]
. I think only literal values can be used as the second argument.
– Szabolcs
Nov 21 at 11:03
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29
6
6
Only a restricted set of forms is supported in
Compile
. You can e.g. DeleteCases[list, 123]
. I think only literal values can be used as the second argument.– Szabolcs
Nov 21 at 11:03
Only a restricted set of forms is supported in
Compile
. You can e.g. DeleteCases[list, 123]
. I think only literal values can be used as the second argument.– Szabolcs
Nov 21 at 11:03
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29
add a comment |
1 Answer
1
active
oldest
votes
up vote
9
down vote
In code for Compile
, it might be a better idea not to delete bad cases but to collect only the good ones with Internal`Bag
.
If you have a certain but reasonably sized upper bound for the number od items to collect, you can also employ this less expensive way, using a packed array instead of a expandable data structure such as Internal`Bag
:
First, preallocate an array a
of sufficient size and a counter c
, initialized by 0
. Then fill the array in a Do
or While
loop: Each time your If
statement evaluates to True
, increase the counter c
and write the "good" item into a[[c]]
. After having collected all items, truncate the array with a[[1;;c]]
.
Example
Here are two functions that search the first n
positive integers for multiples of 3
or 5
:
Internal`Bag
-based version (using the Most[{0}]
hack to initiaize with an empty bag capable of collecting for integers):
cfBag = Compile[{{n, _Integer}},
Block[{bag},
bag = Internal`Bag[Most[{0}]];
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
Internal`StuffBag[bag, i];
],
{i, 1, n}];
Internal`BagPart[bag, All]
],
CompilationTarget -> "C"
];
And here is the array-based version:
cfArray = Compile[{{n, _Integer}},
Block[{a, c = 0},
a = Table[0, {n}];
c = 0;
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
c++;
a[[c]] = i;
],
{i, 1, n}];
If[c > 0, a[[1 ;; c]], {}]
],
CompilationTarget -> "C"
];
Comparison:
r1 = cfBag[10000000]; // RepeatedTiming // First
r2 = cfArray[10000000]; // RepeatedTiming // First
r1 == r2
0.288
0.313
True
To my own surprise, Internal`Bag
is faster. Probably because the task is memory bound and because The reason seems to be that a call like a
is much larger than needed in the end (so, too much memory allocation and a potentially superfluous copy operation in the end).a[[c]] = i;
always checks whether c
is within the bounds of a
. Deactivating that with RuntimeOptions -> "Speed"
makes the two methods equally fast.
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth aboutInternal
Bag` so far, but it sounded interesting to me.
– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
For some reason the example code withInternal`Bag
always seems to be slightly faster than the array based solution. Even with the specification ofRuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.
– Display Name
Nov 21 at 15:23
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily usedCompiled`GetElement
in thea[[c]] += 1
step, instead of usingPart
. I guess there is no equivalent toCompiled`GetElement
for writing operations. As the name suggestsCompiled`GetElement
can of course only be used for read operations.
– Display Name
Nov 22 at 13:18
1
Just need to be careful when you use theWith
construct and replace everything withpart=Compile`GetElement
as you once suggested to me and then not remember the difference betweenpart
andPart
:D
– Display Name
Nov 22 at 13:34
|
show 3 more comments
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
In code for Compile
, it might be a better idea not to delete bad cases but to collect only the good ones with Internal`Bag
.
If you have a certain but reasonably sized upper bound for the number od items to collect, you can also employ this less expensive way, using a packed array instead of a expandable data structure such as Internal`Bag
:
First, preallocate an array a
of sufficient size and a counter c
, initialized by 0
. Then fill the array in a Do
or While
loop: Each time your If
statement evaluates to True
, increase the counter c
and write the "good" item into a[[c]]
. After having collected all items, truncate the array with a[[1;;c]]
.
Example
Here are two functions that search the first n
positive integers for multiples of 3
or 5
:
Internal`Bag
-based version (using the Most[{0}]
hack to initiaize with an empty bag capable of collecting for integers):
cfBag = Compile[{{n, _Integer}},
Block[{bag},
bag = Internal`Bag[Most[{0}]];
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
Internal`StuffBag[bag, i];
],
{i, 1, n}];
Internal`BagPart[bag, All]
],
CompilationTarget -> "C"
];
And here is the array-based version:
cfArray = Compile[{{n, _Integer}},
Block[{a, c = 0},
a = Table[0, {n}];
c = 0;
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
c++;
a[[c]] = i;
],
{i, 1, n}];
If[c > 0, a[[1 ;; c]], {}]
],
CompilationTarget -> "C"
];
Comparison:
r1 = cfBag[10000000]; // RepeatedTiming // First
r2 = cfArray[10000000]; // RepeatedTiming // First
r1 == r2
0.288
0.313
True
To my own surprise, Internal`Bag
is faster. Probably because the task is memory bound and because The reason seems to be that a call like a
is much larger than needed in the end (so, too much memory allocation and a potentially superfluous copy operation in the end).a[[c]] = i;
always checks whether c
is within the bounds of a
. Deactivating that with RuntimeOptions -> "Speed"
makes the two methods equally fast.
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth aboutInternal
Bag` so far, but it sounded interesting to me.
– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
For some reason the example code withInternal`Bag
always seems to be slightly faster than the array based solution. Even with the specification ofRuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.
– Display Name
Nov 21 at 15:23
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily usedCompiled`GetElement
in thea[[c]] += 1
step, instead of usingPart
. I guess there is no equivalent toCompiled`GetElement
for writing operations. As the name suggestsCompiled`GetElement
can of course only be used for read operations.
– Display Name
Nov 22 at 13:18
1
Just need to be careful when you use theWith
construct and replace everything withpart=Compile`GetElement
as you once suggested to me and then not remember the difference betweenpart
andPart
:D
– Display Name
Nov 22 at 13:34
|
show 3 more comments
up vote
9
down vote
In code for Compile
, it might be a better idea not to delete bad cases but to collect only the good ones with Internal`Bag
.
If you have a certain but reasonably sized upper bound for the number od items to collect, you can also employ this less expensive way, using a packed array instead of a expandable data structure such as Internal`Bag
:
First, preallocate an array a
of sufficient size and a counter c
, initialized by 0
. Then fill the array in a Do
or While
loop: Each time your If
statement evaluates to True
, increase the counter c
and write the "good" item into a[[c]]
. After having collected all items, truncate the array with a[[1;;c]]
.
Example
Here are two functions that search the first n
positive integers for multiples of 3
or 5
:
Internal`Bag
-based version (using the Most[{0}]
hack to initiaize with an empty bag capable of collecting for integers):
cfBag = Compile[{{n, _Integer}},
Block[{bag},
bag = Internal`Bag[Most[{0}]];
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
Internal`StuffBag[bag, i];
],
{i, 1, n}];
Internal`BagPart[bag, All]
],
CompilationTarget -> "C"
];
And here is the array-based version:
cfArray = Compile[{{n, _Integer}},
Block[{a, c = 0},
a = Table[0, {n}];
c = 0;
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
c++;
a[[c]] = i;
],
{i, 1, n}];
If[c > 0, a[[1 ;; c]], {}]
],
CompilationTarget -> "C"
];
Comparison:
r1 = cfBag[10000000]; // RepeatedTiming // First
r2 = cfArray[10000000]; // RepeatedTiming // First
r1 == r2
0.288
0.313
True
To my own surprise, Internal`Bag
is faster. Probably because the task is memory bound and because The reason seems to be that a call like a
is much larger than needed in the end (so, too much memory allocation and a potentially superfluous copy operation in the end).a[[c]] = i;
always checks whether c
is within the bounds of a
. Deactivating that with RuntimeOptions -> "Speed"
makes the two methods equally fast.
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth aboutInternal
Bag` so far, but it sounded interesting to me.
– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
For some reason the example code withInternal`Bag
always seems to be slightly faster than the array based solution. Even with the specification ofRuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.
– Display Name
Nov 21 at 15:23
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily usedCompiled`GetElement
in thea[[c]] += 1
step, instead of usingPart
. I guess there is no equivalent toCompiled`GetElement
for writing operations. As the name suggestsCompiled`GetElement
can of course only be used for read operations.
– Display Name
Nov 22 at 13:18
1
Just need to be careful when you use theWith
construct and replace everything withpart=Compile`GetElement
as you once suggested to me and then not remember the difference betweenpart
andPart
:D
– Display Name
Nov 22 at 13:34
|
show 3 more comments
up vote
9
down vote
up vote
9
down vote
In code for Compile
, it might be a better idea not to delete bad cases but to collect only the good ones with Internal`Bag
.
If you have a certain but reasonably sized upper bound for the number od items to collect, you can also employ this less expensive way, using a packed array instead of a expandable data structure such as Internal`Bag
:
First, preallocate an array a
of sufficient size and a counter c
, initialized by 0
. Then fill the array in a Do
or While
loop: Each time your If
statement evaluates to True
, increase the counter c
and write the "good" item into a[[c]]
. After having collected all items, truncate the array with a[[1;;c]]
.
Example
Here are two functions that search the first n
positive integers for multiples of 3
or 5
:
Internal`Bag
-based version (using the Most[{0}]
hack to initiaize with an empty bag capable of collecting for integers):
cfBag = Compile[{{n, _Integer}},
Block[{bag},
bag = Internal`Bag[Most[{0}]];
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
Internal`StuffBag[bag, i];
],
{i, 1, n}];
Internal`BagPart[bag, All]
],
CompilationTarget -> "C"
];
And here is the array-based version:
cfArray = Compile[{{n, _Integer}},
Block[{a, c = 0},
a = Table[0, {n}];
c = 0;
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
c++;
a[[c]] = i;
],
{i, 1, n}];
If[c > 0, a[[1 ;; c]], {}]
],
CompilationTarget -> "C"
];
Comparison:
r1 = cfBag[10000000]; // RepeatedTiming // First
r2 = cfArray[10000000]; // RepeatedTiming // First
r1 == r2
0.288
0.313
True
To my own surprise, Internal`Bag
is faster. Probably because the task is memory bound and because The reason seems to be that a call like a
is much larger than needed in the end (so, too much memory allocation and a potentially superfluous copy operation in the end).a[[c]] = i;
always checks whether c
is within the bounds of a
. Deactivating that with RuntimeOptions -> "Speed"
makes the two methods equally fast.
In code for Compile
, it might be a better idea not to delete bad cases but to collect only the good ones with Internal`Bag
.
If you have a certain but reasonably sized upper bound for the number od items to collect, you can also employ this less expensive way, using a packed array instead of a expandable data structure such as Internal`Bag
:
First, preallocate an array a
of sufficient size and a counter c
, initialized by 0
. Then fill the array in a Do
or While
loop: Each time your If
statement evaluates to True
, increase the counter c
and write the "good" item into a[[c]]
. After having collected all items, truncate the array with a[[1;;c]]
.
Example
Here are two functions that search the first n
positive integers for multiples of 3
or 5
:
Internal`Bag
-based version (using the Most[{0}]
hack to initiaize with an empty bag capable of collecting for integers):
cfBag = Compile[{{n, _Integer}},
Block[{bag},
bag = Internal`Bag[Most[{0}]];
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
Internal`StuffBag[bag, i];
],
{i, 1, n}];
Internal`BagPart[bag, All]
],
CompilationTarget -> "C"
];
And here is the array-based version:
cfArray = Compile[{{n, _Integer}},
Block[{a, c = 0},
a = Table[0, {n}];
c = 0;
Do[
If[Mod[i, 3] == 0 || Mod[i, 5] == 0,
c++;
a[[c]] = i;
],
{i, 1, n}];
If[c > 0, a[[1 ;; c]], {}]
],
CompilationTarget -> "C"
];
Comparison:
r1 = cfBag[10000000]; // RepeatedTiming // First
r2 = cfArray[10000000]; // RepeatedTiming // First
r1 == r2
0.288
0.313
True
To my own surprise, Internal`Bag
is faster. Probably because the task is memory bound and because The reason seems to be that a call like a
is much larger than needed in the end (so, too much memory allocation and a potentially superfluous copy operation in the end).a[[c]] = i;
always checks whether c
is within the bounds of a
. Deactivating that with RuntimeOptions -> "Speed"
makes the two methods equally fast.
edited Nov 21 at 12:27
answered Nov 21 at 11:54
Henrik Schumacher
45.6k466132
45.6k466132
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth aboutInternal
Bag` so far, but it sounded interesting to me.
– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
For some reason the example code withInternal`Bag
always seems to be slightly faster than the array based solution. Even with the specification ofRuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.
– Display Name
Nov 21 at 15:23
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily usedCompiled`GetElement
in thea[[c]] += 1
step, instead of usingPart
. I guess there is no equivalent toCompiled`GetElement
for writing operations. As the name suggestsCompiled`GetElement
can of course only be used for read operations.
– Display Name
Nov 22 at 13:18
1
Just need to be careful when you use theWith
construct and replace everything withpart=Compile`GetElement
as you once suggested to me and then not remember the difference betweenpart
andPart
:D
– Display Name
Nov 22 at 13:34
|
show 3 more comments
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth aboutInternal
Bag` so far, but it sounded interesting to me.
– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
For some reason the example code withInternal`Bag
always seems to be slightly faster than the array based solution. Even with the specification ofRuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.
– Display Name
Nov 21 at 15:23
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily usedCompiled`GetElement
in thea[[c]] += 1
step, instead of usingPart
. I guess there is no equivalent toCompiled`GetElement
for writing operations. As the name suggestsCompiled`GetElement
can of course only be used for read operations.
– Display Name
Nov 22 at 13:18
1
Just need to be careful when you use theWith
construct and replace everything withpart=Compile`GetElement
as you once suggested to me and then not remember the difference betweenpart
andPart
:D
– Display Name
Nov 22 at 13:34
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth about
Internal
Bag` so far, but it sounded interesting to me.– Display Name
Nov 21 at 12:03
Thank you for your answer. Can you maybe provide me with a minimal working example to see how that works out in practice? I only superficially read sth about
Internal
Bag` so far, but it sounded interesting to me.– Display Name
Nov 21 at 12:03
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
Thank you very much. I will take a look at it as soon as I can :)
– Display Name
Nov 21 at 13:17
1
1
For some reason the example code with
Internal`Bag
always seems to be slightly faster than the array based solution. Even with the specification of RuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.– Display Name
Nov 21 at 15:23
For some reason the example code with
Internal`Bag
always seems to be slightly faster than the array based solution. Even with the specification of RuntimeOptions->"Speed"
. At least on my machine. The difference is about 17% of time.– Display Name
Nov 21 at 15:23
1
1
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily used
Compiled`GetElement
in the a[[c]] += 1
step, instead of using Part
. I guess there is no equivalent to Compiled`GetElement
for writing operations. As the name suggests Compiled`GetElement
can of course only be used for read operations.– Display Name
Nov 22 at 13:18
Yes, sry I thought that minor question isn't worth a new question. I also figured out my mistake with the help of your comment. I sloppily used
Compiled`GetElement
in the a[[c]] += 1
step, instead of using Part
. I guess there is no equivalent to Compiled`GetElement
for writing operations. As the name suggests Compiled`GetElement
can of course only be used for read operations.– Display Name
Nov 22 at 13:18
1
1
Just need to be careful when you use the
With
construct and replace everything with part=Compile`GetElement
as you once suggested to me and then not remember the difference between part
and Part
:D– Display Name
Nov 22 at 13:34
Just need to be careful when you use the
With
construct and replace everything with part=Compile`GetElement
as you once suggested to me and then not remember the difference between part
and Part
:D– Display Name
Nov 22 at 13:34
|
show 3 more comments
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f186416%2fcompile-deletecases%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
6
Only a restricted set of forms is supported in
Compile
. You can e.g.DeleteCases[list, 123]
. I think only literal values can be used as the second argument.– Szabolcs
Nov 21 at 11:03
Yes, thank you for pointing it out. I think that is what I encountered here. So it is not usable for my purpose, unfortunately. But I like Henrik's way of avoiding this problem in the first place.
– Display Name
Nov 21 at 15:29