Calculate permutation from Factorial representation of the K-th iteration of the N-th permutation
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
As a follow of a post I made on the Mathematics Stack Exchange I wrote out a simple program that computes the K-th permutation from 0 to N-1 where the number of permutations is N!
. What I was wondering is could I get some pointers on how to improve and re-write the permutation function to be more efficient--e.g. possibly getting rid of the vector and the for-loop to calculate the factorial.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
///<summary>Calculates the permutation of K in range of 0 to N!. (MAX of N = 20--2^61).</summary>
vector<size_t> factorial_permutation(size_t N, uint64_t K)
vector<size_t> Perm;
uint64_t FactN = N, //Factorial of N
RmdrK = K, //Remainder of K/(N-1)!
IterN = N, //Downward iterator for N
PostK; //The factorial position of K for each sub permutation.
for(uint64_t I = N-1; I > 1; I--)
FactN *= I;
for (uint64_t I = 1; I <= N; I++)
FactN /= IterN--;
PostK = RmdrK / FactN;
RmdrK = RmdrK - (PostK * FactN);
Perm.push_back(PostK);
return Perm;
int main()
size_t N = 0;
uint64_t K = 0;
vector<size_t> c = factorial_permutation(N, K);
vector<size_t> s; //The factorial permutation sequence
vector<size_t> e; //The permutation built from the factorial sequence
//Builds the basic order sequence 0 to N-1 before permutation.
for(int i = 0; i < N; i++)
s.push_back(i);
//Pushes the final result converted from factorial permutation to real permutation. For each entry of sequence s[c[i]] is an index into e[i] to build the permutation.
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
// Outputs the final permutation.
for (int i = 0; i < N; i++)
cout << e[i];
cin.get();
;
The function factorial_permutation
calculates the factorial representation of K--the K-th iteration--in a sequence from 0 to (N-1)!
possible permutations. The main()
function does simple conversion from the factorial representation to building the actual sequence. I would like to combine the two and see if I can negate the vectors all together for the sake of performance.
I'm also aware that I can remove the vector in factorial_permutation
by using a basic array, but I can't seem to negate the one in the main()
function.
c++ performance combinatorics
add a comment |Â
up vote
4
down vote
favorite
As a follow of a post I made on the Mathematics Stack Exchange I wrote out a simple program that computes the K-th permutation from 0 to N-1 where the number of permutations is N!
. What I was wondering is could I get some pointers on how to improve and re-write the permutation function to be more efficient--e.g. possibly getting rid of the vector and the for-loop to calculate the factorial.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
///<summary>Calculates the permutation of K in range of 0 to N!. (MAX of N = 20--2^61).</summary>
vector<size_t> factorial_permutation(size_t N, uint64_t K)
vector<size_t> Perm;
uint64_t FactN = N, //Factorial of N
RmdrK = K, //Remainder of K/(N-1)!
IterN = N, //Downward iterator for N
PostK; //The factorial position of K for each sub permutation.
for(uint64_t I = N-1; I > 1; I--)
FactN *= I;
for (uint64_t I = 1; I <= N; I++)
FactN /= IterN--;
PostK = RmdrK / FactN;
RmdrK = RmdrK - (PostK * FactN);
Perm.push_back(PostK);
return Perm;
int main()
size_t N = 0;
uint64_t K = 0;
vector<size_t> c = factorial_permutation(N, K);
vector<size_t> s; //The factorial permutation sequence
vector<size_t> e; //The permutation built from the factorial sequence
//Builds the basic order sequence 0 to N-1 before permutation.
for(int i = 0; i < N; i++)
s.push_back(i);
//Pushes the final result converted from factorial permutation to real permutation. For each entry of sequence s[c[i]] is an index into e[i] to build the permutation.
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
// Outputs the final permutation.
for (int i = 0; i < N; i++)
cout << e[i];
cin.get();
;
The function factorial_permutation
calculates the factorial representation of K--the K-th iteration--in a sequence from 0 to (N-1)!
possible permutations. The main()
function does simple conversion from the factorial representation to building the actual sequence. I would like to combine the two and see if I can negate the vectors all together for the sake of performance.
I'm also aware that I can remove the vector in factorial_permutation
by using a basic array, but I can't seem to negate the one in the main()
function.
c++ performance combinatorics
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
As a follow of a post I made on the Mathematics Stack Exchange I wrote out a simple program that computes the K-th permutation from 0 to N-1 where the number of permutations is N!
. What I was wondering is could I get some pointers on how to improve and re-write the permutation function to be more efficient--e.g. possibly getting rid of the vector and the for-loop to calculate the factorial.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
///<summary>Calculates the permutation of K in range of 0 to N!. (MAX of N = 20--2^61).</summary>
vector<size_t> factorial_permutation(size_t N, uint64_t K)
vector<size_t> Perm;
uint64_t FactN = N, //Factorial of N
RmdrK = K, //Remainder of K/(N-1)!
IterN = N, //Downward iterator for N
PostK; //The factorial position of K for each sub permutation.
for(uint64_t I = N-1; I > 1; I--)
FactN *= I;
for (uint64_t I = 1; I <= N; I++)
FactN /= IterN--;
PostK = RmdrK / FactN;
RmdrK = RmdrK - (PostK * FactN);
Perm.push_back(PostK);
return Perm;
int main()
size_t N = 0;
uint64_t K = 0;
vector<size_t> c = factorial_permutation(N, K);
vector<size_t> s; //The factorial permutation sequence
vector<size_t> e; //The permutation built from the factorial sequence
//Builds the basic order sequence 0 to N-1 before permutation.
for(int i = 0; i < N; i++)
s.push_back(i);
//Pushes the final result converted from factorial permutation to real permutation. For each entry of sequence s[c[i]] is an index into e[i] to build the permutation.
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
// Outputs the final permutation.
for (int i = 0; i < N; i++)
cout << e[i];
cin.get();
;
The function factorial_permutation
calculates the factorial representation of K--the K-th iteration--in a sequence from 0 to (N-1)!
possible permutations. The main()
function does simple conversion from the factorial representation to building the actual sequence. I would like to combine the two and see if I can negate the vectors all together for the sake of performance.
I'm also aware that I can remove the vector in factorial_permutation
by using a basic array, but I can't seem to negate the one in the main()
function.
c++ performance combinatorics
As a follow of a post I made on the Mathematics Stack Exchange I wrote out a simple program that computes the K-th permutation from 0 to N-1 where the number of permutations is N!
. What I was wondering is could I get some pointers on how to improve and re-write the permutation function to be more efficient--e.g. possibly getting rid of the vector and the for-loop to calculate the factorial.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
///<summary>Calculates the permutation of K in range of 0 to N!. (MAX of N = 20--2^61).</summary>
vector<size_t> factorial_permutation(size_t N, uint64_t K)
vector<size_t> Perm;
uint64_t FactN = N, //Factorial of N
RmdrK = K, //Remainder of K/(N-1)!
IterN = N, //Downward iterator for N
PostK; //The factorial position of K for each sub permutation.
for(uint64_t I = N-1; I > 1; I--)
FactN *= I;
for (uint64_t I = 1; I <= N; I++)
FactN /= IterN--;
PostK = RmdrK / FactN;
RmdrK = RmdrK - (PostK * FactN);
Perm.push_back(PostK);
return Perm;
int main()
size_t N = 0;
uint64_t K = 0;
vector<size_t> c = factorial_permutation(N, K);
vector<size_t> s; //The factorial permutation sequence
vector<size_t> e; //The permutation built from the factorial sequence
//Builds the basic order sequence 0 to N-1 before permutation.
for(int i = 0; i < N; i++)
s.push_back(i);
//Pushes the final result converted from factorial permutation to real permutation. For each entry of sequence s[c[i]] is an index into e[i] to build the permutation.
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
// Outputs the final permutation.
for (int i = 0; i < N; i++)
cout << e[i];
cin.get();
;
The function factorial_permutation
calculates the factorial representation of K--the K-th iteration--in a sequence from 0 to (N-1)!
possible permutations. The main()
function does simple conversion from the factorial representation to building the actual sequence. I would like to combine the two and see if I can negate the vectors all together for the sake of performance.
I'm also aware that I can remove the vector in factorial_permutation
by using a basic array, but I can't seem to negate the one in the main()
function.
c++ performance combinatorics
edited Feb 27 at 17:14
asked Feb 27 at 0:44
FatalSleep
22119
22119
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11
add a comment |Â
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
4
down vote
The loop
for(int i = 0; i < N; i++)
s.push_back(i);is idiomatically expressed as
std::iota(s.begin(), s.end(), 0)
(you'd need to#include <numeric>
).A no naked loops principle demands giving a name to the
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
loop. It surely represents an important algorithm. What exactly does it do?
In any case, the
s
ande
vectors shall not be exposed to the client.Computing factorials restricts the utility of the code to
N < 21
(21! = 0x2_c507_7d36_b8c4_0000
doesn't fit in 64 bits). Unfortunately you cannot even expressK
withinuint64_t
limits for largerN
. ConsiderBigInteger
.It is possible to avoid factorials (as well as ancillary vectors) by working other way around. Consider a pseudocode:
while N > 0:
index = K % N
swap a[N-1] with a[index]
K /= N
N -= 1While correct, it doesn't produce the same
K
'th permutation as your code does. May I suggest changing it to produce the correct sequence as an exercise?
PS: a mandatory warning on using namespace std
2
std::iota()
isn't a direct replacement there - it's a shame there's nostd::iota_n
that could take a back-insert iterator.
â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunatelystd:iota()
doesn't work here ifs
is a length of 0. Unless I defineds
asvector<uint64_t> s(N);
which might save some performance, if any.
â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers theN!
number of permutations requirements.
â FatalSleep
Feb 27 at 17:30
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
The loop
for(int i = 0; i < N; i++)
s.push_back(i);is idiomatically expressed as
std::iota(s.begin(), s.end(), 0)
(you'd need to#include <numeric>
).A no naked loops principle demands giving a name to the
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
loop. It surely represents an important algorithm. What exactly does it do?
In any case, the
s
ande
vectors shall not be exposed to the client.Computing factorials restricts the utility of the code to
N < 21
(21! = 0x2_c507_7d36_b8c4_0000
doesn't fit in 64 bits). Unfortunately you cannot even expressK
withinuint64_t
limits for largerN
. ConsiderBigInteger
.It is possible to avoid factorials (as well as ancillary vectors) by working other way around. Consider a pseudocode:
while N > 0:
index = K % N
swap a[N-1] with a[index]
K /= N
N -= 1While correct, it doesn't produce the same
K
'th permutation as your code does. May I suggest changing it to produce the correct sequence as an exercise?
PS: a mandatory warning on using namespace std
2
std::iota()
isn't a direct replacement there - it's a shame there's nostd::iota_n
that could take a back-insert iterator.
â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunatelystd:iota()
doesn't work here ifs
is a length of 0. Unless I defineds
asvector<uint64_t> s(N);
which might save some performance, if any.
â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers theN!
number of permutations requirements.
â FatalSleep
Feb 27 at 17:30
add a comment |Â
up vote
4
down vote
The loop
for(int i = 0; i < N; i++)
s.push_back(i);is idiomatically expressed as
std::iota(s.begin(), s.end(), 0)
(you'd need to#include <numeric>
).A no naked loops principle demands giving a name to the
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
loop. It surely represents an important algorithm. What exactly does it do?
In any case, the
s
ande
vectors shall not be exposed to the client.Computing factorials restricts the utility of the code to
N < 21
(21! = 0x2_c507_7d36_b8c4_0000
doesn't fit in 64 bits). Unfortunately you cannot even expressK
withinuint64_t
limits for largerN
. ConsiderBigInteger
.It is possible to avoid factorials (as well as ancillary vectors) by working other way around. Consider a pseudocode:
while N > 0:
index = K % N
swap a[N-1] with a[index]
K /= N
N -= 1While correct, it doesn't produce the same
K
'th permutation as your code does. May I suggest changing it to produce the correct sequence as an exercise?
PS: a mandatory warning on using namespace std
2
std::iota()
isn't a direct replacement there - it's a shame there's nostd::iota_n
that could take a back-insert iterator.
â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunatelystd:iota()
doesn't work here ifs
is a length of 0. Unless I defineds
asvector<uint64_t> s(N);
which might save some performance, if any.
â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers theN!
number of permutations requirements.
â FatalSleep
Feb 27 at 17:30
add a comment |Â
up vote
4
down vote
up vote
4
down vote
The loop
for(int i = 0; i < N; i++)
s.push_back(i);is idiomatically expressed as
std::iota(s.begin(), s.end(), 0)
(you'd need to#include <numeric>
).A no naked loops principle demands giving a name to the
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
loop. It surely represents an important algorithm. What exactly does it do?
In any case, the
s
ande
vectors shall not be exposed to the client.Computing factorials restricts the utility of the code to
N < 21
(21! = 0x2_c507_7d36_b8c4_0000
doesn't fit in 64 bits). Unfortunately you cannot even expressK
withinuint64_t
limits for largerN
. ConsiderBigInteger
.It is possible to avoid factorials (as well as ancillary vectors) by working other way around. Consider a pseudocode:
while N > 0:
index = K % N
swap a[N-1] with a[index]
K /= N
N -= 1While correct, it doesn't produce the same
K
'th permutation as your code does. May I suggest changing it to produce the correct sequence as an exercise?
PS: a mandatory warning on using namespace std
The loop
for(int i = 0; i < N; i++)
s.push_back(i);is idiomatically expressed as
std::iota(s.begin(), s.end(), 0)
(you'd need to#include <numeric>
).A no naked loops principle demands giving a name to the
for (int i = 0; i < N; i++)
e.push_back(s[c[i]]);
s.erase(s.begin() + c[i]);
loop. It surely represents an important algorithm. What exactly does it do?
In any case, the
s
ande
vectors shall not be exposed to the client.Computing factorials restricts the utility of the code to
N < 21
(21! = 0x2_c507_7d36_b8c4_0000
doesn't fit in 64 bits). Unfortunately you cannot even expressK
withinuint64_t
limits for largerN
. ConsiderBigInteger
.It is possible to avoid factorials (as well as ancillary vectors) by working other way around. Consider a pseudocode:
while N > 0:
index = K % N
swap a[N-1] with a[index]
K /= N
N -= 1While correct, it doesn't produce the same
K
'th permutation as your code does. May I suggest changing it to produce the correct sequence as an exercise?
PS: a mandatory warning on using namespace std
answered Feb 27 at 4:43
vnp
36.5k12991
36.5k12991
2
std::iota()
isn't a direct replacement there - it's a shame there's nostd::iota_n
that could take a back-insert iterator.
â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunatelystd:iota()
doesn't work here ifs
is a length of 0. Unless I defineds
asvector<uint64_t> s(N);
which might save some performance, if any.
â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers theN!
number of permutations requirements.
â FatalSleep
Feb 27 at 17:30
add a comment |Â
2
std::iota()
isn't a direct replacement there - it's a shame there's nostd::iota_n
that could take a back-insert iterator.
â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunatelystd:iota()
doesn't work here ifs
is a length of 0. Unless I defineds
asvector<uint64_t> s(N);
which might save some performance, if any.
â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers theN!
number of permutations requirements.
â FatalSleep
Feb 27 at 17:30
2
2
std::iota()
isn't a direct replacement there - it's a shame there's no std::iota_n
that could take a back-insert iterator.â Toby Speight
Feb 27 at 8:44
std::iota()
isn't a direct replacement there - it's a shame there's no std::iota_n
that could take a back-insert iterator.â Toby Speight
Feb 27 at 8:44
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
Thank you for the answer I've revised my code to include comments. My apologies it's not the best code/commented. I mocked it up really quick.
â FatalSleep
Feb 27 at 17:15
@vnp unfortunately
std:iota()
doesn't work here if s
is a length of 0. Unless I defined s
as vector<uint64_t> s(N);
which might save some performance, if any.â FatalSleep
Feb 27 at 17:25
@vnp unfortunately
std:iota()
doesn't work here if s
is a length of 0. Unless I defined s
as vector<uint64_t> s(N);
which might save some performance, if any.â FatalSleep
Feb 27 at 17:25
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers the
N!
number of permutations requirements.â FatalSleep
Feb 27 at 17:30
@vnp I'll try out your changes here and get back to you. I don't care how it produces the permutations, just that it produces them faster and without duplicates and covers the
N!
number of permutations requirements.â FatalSleep
Feb 27 at 17:30
add a comment |Â
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
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188413%2fcalculate-permutation-from-factorial-representation-of-the-k-th-iteration-of-the%23new-answer', 'question_page');
);
Post as a guest
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
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
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
Any particular C++ standard you are using for this? C++11/14/17?
â Arnav Borborah
Feb 27 at 1:23
Doesn't matter. For sake of reference, C++17.
â FatalSleep
Feb 27 at 2:11