Iwas reading about group theory recently, for basic cryptography, and wanted a function for computing the set , i.e. the set of integers with greatest common divisor (gcd) with
equal to
, formally
.
And I wanted to do it “quickly”, in a math engine, so what better place than on Wolfram’s Development Platform!
It’s not rocket science how to compute the set, but I thought this’d serve as a nice reference, with examples, to basic operations in the Wolfram Language on the Wolfram Cloud.
I needed to be able to check the gcd between numbers, this is built in as GCD, example
in: GCD[4,6]; out: 2
Checking from 1..n-1 is tedious however, where Do comes in handy. Do[ expr, { var, limit } ], loops var from 1 to limit (inclusive), example
In: Do[GCD[n,6], {n,6}];
Out: // nothing's output as Do just performs the calculation.
Time for Print[expr]! Example
In: Do[Print[GCD[n,6]], {n,6}];
Out: 1
2
3
2
1
6
But this is badly formatted, and also it includes the check of gcd(6,6), and it has a hardcoded variable. First, into a function, example
In: f[x_] := 42 + x; f[2]; Out: 44
Calculates the answer to life, the universe and everything, plus x, i.e. 2. Our function looks like, (variable factored out, removed gcd(n,n) check with g-1)
In: CalcSet[g_]:= Do[Print[GCD[n,g]], {n,g-1}];
CalcSet[6];
Out: 1
2
3
2
1
6
Still badly formatted, and actually it doesn’t output the set, just a list of tests where it prints the restult of GCD; enter If. If[ expr, t, f], where t is evaluated if expr is true, and f is an optional expression, evaluated if expr evaluates to false. (If no f is provided, and the If is used in something bigger, say a list, it’ll return null). Start small:
In: If[ 1==1, Print["true"], Print["false"]]; (* prints "true" *) If[ 1==2, Print["true"], Print["false"]]; (* prints "false" *) If[ 1==2, Print["true"]];(* does nothing *) If[ 1==1, Print["true"]]; (* prints "true" *) Out: "true" "false" "true"
Redefine function with the If-condition
In: CalcSet[g_]:= Do[If[GCD[n,g] == 1, Print[n]], {n,g}];
CalcSet[6];
Out: 1
5
I love it, I can compute the set! Still it isn’t very nicely formatted; I want it in a list. So I need a list, and the AppendTo function,
In: l = {1, 2};
AppendTo[l, 3];
Print[l];
out: {1, 2, 3}
Putting it all together in a ()-clause, extracting the Print I get the final code:
In: GenSet[g_]:= (
l={};
Do[If[GCD[n,g] == 1, AppendTo[l,n]], {n,g-1}];
Return[l];
);
Print[GenSet[6]];
Out: {1, 5}
Print[GenSet[5]];
Out: {1, 2, 3, 4}
Print[GenSet[10]];
Out: {1, 3. 7, 9}
This could probably be optimized further by adding 1 to the initial set, and skip the first check, like below (Do with a { var, start, end }-constraint),
In: GenSetOptimized[g_]:= (
l={1};
Do[If[GCD[n,g] == 1, AppendTo[l,n]], {n,2,g-1}];
Return[l];
);
Print[GenSetOptimized[6]];
Out: {1, 5}
But it’s not a race!!.. I wonder if this can be done with a map somehow, in a sane way. In my head it doesn’t seem faster(, or less involved!)
Also, I totally know that I’m cheating by not calculating gcd(n,n), but I made the clever observation that it’ll never be 1 unless n is 1 (I’ll leave it up to the reader to prove this.) The function doesn’t work for generating either; suppose we’ll have to wonder for eternity what the result of this is.
Edit: lol wait, it actually does work in the optimized version, since it adds 1 to the set initially and just skips the Do-loop. I totally knew this; which is why I made the optimized version, I promise.
