Improved & new sampling algorithms

This PR improves & implements algorithms for sampling with/without replacement. 

With this PR, we now have the following algorithms:

**with replacement:**

- direct sampling
- expanded multinomial sampling

**without replacement:**

- Knuth's Algorithm S
- Fisher-Yates shuffling (with early termination)
- Self-avoid sampling (using a set)
- Sequential sampling based on Jeffrey Scott Vitter's paper (Algorithm A & Algorithm C)

The function `sample` is a poly-algorithm: the rules for making choices are based on extensive benchmarks.