Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tuneup sampling in C++(with classic functions) #59

Merged
merged 1 commit into from
Oct 21, 2021
Merged

Conversation

azriel1rf
Copy link
Collaborator

@azriel1rf azriel1rf commented Oct 21, 2021

continue from #56
I cannot reopen and opened another PR.

More fast implementation is available

Unit comparison

result

310 ms
29 20 2 1 25 32 4 3 46 
36 8 24 29 15 7 30 34 28 
0 34 40 23 1 18 5 7 32 

proposal
72 ms
30 15 40 16 18 14 51 36 9 
3 24 14 17 35 42 34 39 41 
9 22 41 5 3 48 17 14 42

roughly implementation

class CardSampler {
  std::array<int, 52> deck;
public:
  CardSampler(void) {
    for (int i = 0; i < deck.size(); i++) {
      deck[i] = i;
    }
  }
  std::vector<int> sample(int size) {
    std::vector<int> ret;
    int residual_cards = deck.size();
    for (int i = 0; i < size; i++) {
      int target_index = generator() % residual_cards;
      int tail_index = residual_cards - 1;
      std::swap(deck[target_index], deck[tail_index]);
      ret.push_back(deck[tail_index]);
      residual_cards--;
    }
    return ret;
  }
};

comparison source code

#include <algorithm>
#include <array>
#include <iostream>
#include <map>
#include <random>
#include <string>
#include <type_traits>
#include <vector>
#include <utility>
#include <ctime>
#include <chrono>
#include <set>
#include <unordered_set>
#include <numeric>

using std::array;
using std::cout;
using std::endl;
using std::map;
using std::string;
using std::unordered_map;
using std::vector;

void print(auto const& a) {
  for (auto const& e : a) cout << e << ' ';
  cout << "\n";
}

static unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
static std::default_random_engine generator(seed);
static std::uniform_int_distribution<int> distribution(0, 51);

static std::vector<int> RandomCardSample(int size) {
  std::vector<int> ret;
  std::set<int> sample;

  while (sample.size() < size) {
    int number = distribution(generator);
    if (sample.find(number) == sample.end()) {
      ret.push_back(number);
      sample.insert(number);
    }
  }

  return ret;
}

class CardSampler {
  std::array<int, 52> deck;
public:
  CardSampler(void) {
    for (int i = 0; i < deck.size(); i++) {
      deck[i] = i;
    }
  }
  std::vector<int> sample(int size) {
    std::vector<int> ret;
    int residual_cards = deck.size();
    for (int i = 0; i < size; i++) {
      int target_index = generator() % residual_cards;
      int tail_index = residual_cards - 1;
      std::swap(deck[target_index], deck[tail_index]);
      ret.push_back(deck[tail_index]);
      residual_cards--;
    }
    return ret;
  }
};



int main() {
  int repetition = 100000;
  cout << "current" << endl;
  std::clock_t begin = std::clock();
  for (int i = 0; i < repetition; i++) {
    RandomCardSample(9);
  }
  cout << (clock() - begin) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
  print(RandomCardSample(9));
  print(RandomCardSample(9));
  print(RandomCardSample(9));
  cout << endl;

  cout << "proposal" << endl;
  CardSampler cs{};
  begin = std::clock();
  for (int i = 0; i < repetition; i++) {
    cs.sample(9);
  }
  cout << (clock() - begin) * 1000 / CLOCKS_PER_SEC << " ms" << endl;
  print(cs.sample(9));
  print(cs.sample(9));
  print(cs.sample(9));
  cout << endl;
}

I thought there are better way without class just only function but I cannot create 0~51 array in compiling time.

@azriel1rf azriel1rf marked this pull request as draft October 21, 2021 07:10
@azriel1rf azriel1rf force-pushed the tuneup_sampler branch 3 times, most recently from 5c20725 to 1025a87 Compare October 21, 2021 07:13
@azriel1rf azriel1rf requested a review from HenryRLee October 21, 2021 07:18
@azriel1rf
Copy link
Collaborator Author

I referenced Fisher–Yates shuffle and its modern algorithm.
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm

@azriel1rf azriel1rf self-assigned this Oct 21, 2021
@azriel1rf azriel1rf added the c++ label Oct 21, 2021
@azriel1rf azriel1rf marked this pull request as ready for review October 21, 2021 07:32
HenryRLee
HenryRLee previously approved these changes Oct 21, 2021
Copy link
Owner

@HenryRLee HenryRLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Just left a comment for the std::iota. You can merge the PR with squash and merge if you feel it's ready. Thanks for your work!

*tuneup sampling in C++

*revert

*replace for loop with iota
@azriel1rf
Copy link
Collaborator Author

I cannot merge PR after pushing another commit.

Copy link
Owner

@HenryRLee HenryRLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Thank you.

@HenryRLee HenryRLee merged commit 4a66d26 into master Oct 21, 2021
@azriel1rf azriel1rf deleted the tuneup_sampler branch October 24, 2021 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants