LibraryLink function
My intuition was off for Compile
, so I had to see if things worked like I expected in C using LibraryLink. Here is the C code.
#include <stdio.h>
#include "WolframLibrary.h"
#include <stdbool.h>
#include <limits.h>
DLLEXPORT mint WolframLibrary_getVersion( ) {
return WolframLibraryVersion;}
DLLEXPORT int WolframLibrary_initialize( WolframLibraryData libData){
return LIBRARY_NO_ERROR;}
DLLEXPORT void WolframLibrary_uninitialize( WolframLibraryData
libData) {
return;}
DLLEXPORT int nonMultsCondManMod(WolframLibraryData libData,
mint Argc, MArgument *Args, MArgument Res)
{
int err = LIBRARY_NO_ERROR;
mint nn = MArgument_getInteger(Args[0]);
mint mm = MArgument_getInteger(Args[1]);
mint quot = nn/mm;
mint rem = nn - quot*mm;
mint resLen = (mm-1)*quot + rem;
MTensor result;
err = libData->MTensor_new(MType_Integer, 1, &resLen, &result);
mint* dataPtr = libData->MTensor_getIntegerData(result);
int ii;
int jj = 1;
int kk = 1;
for (ii = 1; ii <= resLen; ii++) {
*(dataPtr++) = jj++;
if(kk == mm-1){
jj++;
kk = 1;
} else{kk++;}
}
MArgument_setMTensor(Res, result);
return LIBRARY_NO_ERROR;
}
To let Mathematica use the C code, we will make a string of the code and store it in the variable cCodeString
. To do this, copy the code above, paste it between quotes ""
and click "Yes" in the dialog (to escape the characters).
cCodeString = (*Insert C code here*);
Now we process the code/string and make a function out of it.
<< CCompilerDriver`;
CreateLibrary[cCodeString, "nonMults"];
Quiet@LibraryUnload["nonMults"];
nonMultsCondManMod =
LibraryFunctionLoad["nonMults",
"nonMultsCondManMod", {Integer, Integer}, {Integer, 1}];
Timing comparison
mm = 4;
nn = 10^7;
(rJ = nonMultsCondManMod[nn, mm]) // RepeatedTiming // First
(rW1 = Drop[Range@nn, {mm, -1, mm}]) // RepeatedTiming // First
rJ === rW1
0.018
0.056
True
Sillyness
It seems my intuition was a bit off and the kind of strategy shown below only works (kind of) nicely in C, see for example the code above, or here or here. The simple code by Mr.Wizard is faster. I'll refrain from deleting the code below despite this.
This solution uses Compile
. It also uses meta-programming to avoid any conditionals (If
) or restructuring (Select
, Pick
), while still being quite general. Evaluate all the code again if you want to try e.g. mm=2
(make a list of odd numbers). Of course all this overkill in a sense.
mm = 4;
hCompileBodyTemplate =
# /. OwnValues[mm] &@
Hold[
quot = Quotient[nn, mm];
rem = nn - quot*mm;
res = ConstantArray[0, quot*(mm - 1) + rem];
ii = 1;
jj = 1;
Do[
token;
jj++;
,
quot
];
Do[
res[[ii++]] = jj++
,
rem
];
res
];
hInstructions =
CompoundExpression @@@
Hold @@
Join @@@
List@
Table[
Hold[res[[ii++]] = jj++]
,
mm - 1
];
hTokenRule =
Delete[Hold @@ {HoldPattern[token] -> hInstructions}, {1, 2, 0}];
hCompileBody =
ReplaceAll @@ {
hCompileBodyTemplate,
Unevaluated @@ hTokenRule
};
hToken2Rule =
Delete[Hold @@ {HoldPattern[token2] -> hCompileBody}, {1, 2, 0}];
hCompileTemplate =
Hold@
Compile[
{{nn, _Integer}},
Block[{quot, rem, ii, jj, res},
token2
]
];
heldCompile =
ReplaceAll @@ {
hCompileTemplate,
Unevaluated @@ hToken2Rule
};
cfu = Identity @@ heldCompile;
Example
cfu[22]
{1,2,3,5,6,7,9,10,11,13,14,15,17,18,19,21,22}
Message to OP (Mariam)
I really directed my answer to other experienced users of this site. Perhaps I should have been more clear. Thank you for your message, now that I know that you intend to study all the answers I will try to make my answer more readable and educational.
There are at least two things that can be learned from this answer
- There is a function
Compile
that can make certain code faster
- In the Wolfram Language (Mathematica) you can use code to generate and/or manipulate code
With regards to point 1., that is, the fact that Compile
exists, I would like to say that it can be tricky to get started with Compile
, because it requires some specific knowledge of what code can be compiled.
Concerning point 2, this manipulation and generation of code can be called meta-programming. This arguably an even more advanced (and useless) topic than Compile
.
For example C++ also has some abilities to do meta-programming, mostly because of its flexible preprocessor, which is really a language all by itself. One (kind of) special thing about meta-programming in Mathematica is that you can use (many of) the same functions that would normally use to manipulate data to instead manipulate code.
In my answer I first generate some instructions and then insert them into my code. You can see that the token
in the code above was replaced by three identical instructions res[[ii++]] = jj++;
. The code that is generated looks as follows.
quot = Quotient[nn, 4];
rem = nn - quot 4;
res = ConstantArray[0, quot (4 - 1) + rem];
ii = 1;
jj = 1;
Do[
(res[[ii++]] = jj++;
res[[ii++]] = jj++;
res[[ii++]] = jj++); jj++;,
quot
];
Do[
res[[ii++]] = jj++,
rem];
res
Instead of bothering with how meta-programming or Compile
works, perhaps you can first try to see why the generated code works for your question. A simpler version of the code above is this
nn = 22;
mm = 4;
quot = Quotient[nn, mm];
rem = nn - quot * mm;
resultLength = quot (mm - 1) + rem;
res = ConstantArray[0, resultLength];
jj = 1;
Do[
res[[ii++]] = jj++;
If[
Divisible[jj , mm],
jj++
]
,
{ii, 1, resultLength}
];
res
And making it "more normal", we get this
nn = 22;
mm = 4;
quot = Quotient[nn, mm];
rem = nn - quot * mm;
resultLength = quot (mm - 1) + rem;
jj = 0;
res =
Table[
jj++;
If[Divisible[jj , mm], jj++];
jj
,
{ii, 1, resultLength}
]
If we do not try to be so clever to predict the length of the result beforehand, we can end up with something that was already mentioned in other answers
nn = 22;
mm = 4;
res =
Table[
If[Divisible[jj , mm], Nothing, jj]
,
{jj, 1, nn}
]
I recommend starting with this last piece of code and trying to see why the piece of code above it does the same thing.
range1[n_] := Floor[Range[1, n + 3/4, 4/3]]
$\endgroup$Flatten@Outer[Plus, 4 Range[0, 24], Range[3]]
. (It produces a packed array.) $\endgroup$