Skip to content

Models

shuffl.models

This module provides several different mathematical models for shuffling cards.

The implemented models include:

  • gsr: Gilbert-Shannon-Reeds model for riffle shuffling
  • thorp: Thorp model for riffle shuffling
  • strip: Coin-toss model for strip or overhand shuffling
  • cut: Model for cutting a deck about in half

gsr(deck)

Gilbert-Shannon-Reeds model for riffle shuffling.

A deck of n cards is cut about in half according to a binomial distribution. The cards from the two packets are then riffled in such a way, that the probability of dropping a card from either half is proportional to the respective packet size.

There are several analogous interpretations of the GSR model. This function implements the geometric interpretation.

Example:

from shuffl.models import gsr
from shuffl import Deck

# Create a deck of 52 cards
deck = Deck(range(1,53))

# Apply the shuffle
shuffled_deck = gsr(deck)

# Print the shuffled deck
print(shuffled_deck)

References:

  • Bayer D., Diaconis P. (1992). Trailing the dovetail shuffle to its lair. The Annals of Applied Probability, Vol. 2, No. 2, 294-313
PARAMETER DESCRIPTION
deck

A deck of cards

TYPE: Deck

RETURNS DESCRIPTION
Deck

The shuffled deck

Source code in shuffl/models/_gsr.py
def gsr(
    deck: Annotated[Deck, Doc("A deck of cards")],
) -> Annotated[Deck, Doc("The shuffled deck")]:
    """Gilbert-Shannon-Reeds model for riffle shuffling.

    A deck of n cards is cut about in half according to a binomial
    distribution. The cards from the two packets are then riffled in
    such a way, that the probability of dropping a card from either
    half is proportional to the respective packet size.

    There are several analogous interpretations of the GSR model.
    This function implements the geometric interpretation.

    **Example:**

    ```python
    from shuffl.models import gsr
    from shuffl import Deck

    # Create a deck of 52 cards
    deck = Deck(range(1,53))

    # Apply the shuffle
    shuffled_deck = gsr(deck)

    # Print the shuffled deck
    print(shuffled_deck)
    ```

    **References:**

    - Bayer D., Diaconis P. (1992). Trailing the dovetail shuffle to its lair.
    The Annals of Applied Probability, Vol. 2, No. 2, 294-313
    """
    x = np.sort(np.random.uniform(low=0, high=1, size=len(deck)))
    y = 2 * x % 1
    return Deck([deck[i] for i in np.argsort(y)])

thorp(deck)

Thorp model for riffle shuffling.

The model cuts a deck of 2n cards into two packets of size n, and then starts dropping the cards from the left or right hand, such that each time one chooses the left or right card with probability 1/2 and then drops the card from the opposite hand.

Example:

from shuffl.models import thorp
from shuffl import Deck

# Create a deck of 52 cards
deck = Deck(range(1,53))

# Apply the shuffle
shuffled_deck = thorp(deck)

# Print the shuffled deck
print(shuffled_deck)

References:

  • Thorp E. O. (1973). Nonrandom shuffling with applications to the game of Faro. Journal of the American Statistical Association, Vol. 68, No. 344, 842-847.
PARAMETER DESCRIPTION
deck

A deck of cards

TYPE: Deck

RETURNS DESCRIPTION
Deck

The shuffled deck

Source code in shuffl/models/_thorp.py
def thorp(
    deck: Annotated[Deck, Doc("A deck of cards")],
) -> Annotated[Deck, Doc("The shuffled deck")]:
    """Thorp model for riffle shuffling.

    The model cuts a deck of _2n_ cards into two packets of size n, and
    then starts dropping the cards from the left or right hand, such that
    each time one chooses the left or right card with probability 1/2 and
    then drops the card from the opposite hand.

    **Example:**

    ```python
    from shuffl.models import thorp
    from shuffl import Deck

    # Create a deck of 52 cards
    deck = Deck(range(1,53))

    # Apply the shuffle
    shuffled_deck = thorp(deck)

    # Print the shuffled deck
    print(shuffled_deck)
    ```

    **References:**

    - Thorp E. O. (1973). Nonrandom shuffling with applications to the game of Faro.
    Journal of the American Statistical Association, Vol. 68, No. 344, 842-847.
    """
    n = int(len(deck) / 2)
    cointoss = np.random.binomial(1, 0.5, n)
    left, right = deck[:n], deck[n:]
    shuffled = []
    for c in cointoss:
        if c == 0:
            shuffled.extend([left.pop(0), right.pop(0)])
        else:
            shuffled.extend([right.pop(0), left.pop(0)])
    return Deck(shuffled)

strip(deck)

Coin toss model for strip cutting a deck of cards.

The implementation is based on the coin toss interpretation of the strip shuffle.

Example:

from shuffl.models import strip
from shuffl import Deck

# Create a deck of 52 cards
deck = Deck(range(1,53))

# Apply the shuffle
shuffled_deck = strip(deck)

# Print the shuffled deck
print(shuffled_deck)
PARAMETER DESCRIPTION
deck

A deck of cards

TYPE: Deck

RETURNS DESCRIPTION
Deck

The shuffled deck

Source code in shuffl/models/_strip.py
def strip(
    deck: Annotated[Deck, Doc("A deck of cards")],
) -> Annotated[Deck, Doc("The shuffled deck")]:
    """Coin toss model for strip cutting a deck of cards.

    The implementation is based on the coin toss interpretation
    of the strip shuffle.

    **Example:**

    ```python
    from shuffl.models import strip
    from shuffl import Deck

    # Create a deck of 52 cards
    deck = Deck(range(1,53))

    # Apply the shuffle
    shuffled_deck = strip(deck)

    # Print the shuffled deck
    print(shuffled_deck)
    ```
    """
    n = int(len(deck))
    cointoss = np.random.binomial(1, 0.2, n - 1)
    breakpoints = (np.flatnonzero(cointoss) + 1).tolist()
    split_packets = np.split(deck, breakpoints)
    return Deck([s for p in reversed(split_packets) for s in p])

cut(deck)

Model for cutting a deck about in half and completing the cut.

Cuts a given deck according to a binomial distribution.

Example:

from shuffl.models import cut
from shuffl import Deck

# Create a deck of 52 cards
deck = Deck(range(1,53))

# Apply the shuffle
shuffled_deck = cut(deck)

# Print the shuffled deck
print(shuffled_deck)

References:

  • Bayer D., Diaconis P. (1992). Trailing the dovetail shuffle to its lair. The Annals of Applied Probability, Vol. 2, No. 2, 294-313.
PARAMETER DESCRIPTION
deck

A deck of cards

TYPE: Deck

RETURNS DESCRIPTION
Deck

The shuffled deck

Source code in shuffl/models/_cut.py
def cut(
    deck: Annotated[Deck, Doc("A deck of cards")],
) -> Annotated[Deck, Doc("The shuffled deck")]:
    """Model for cutting a deck about in half and completing
    the cut.

    Cuts a given deck according to a binomial distribution.

    **Example:**

    ```python
    from shuffl.models import cut
    from shuffl import Deck

    # Create a deck of 52 cards
    deck = Deck(range(1,53))

    # Apply the shuffle
    shuffled_deck = cut(deck)

    # Print the shuffled deck
    print(shuffled_deck)
    ```

    **References:**

    - Bayer D., Diaconis P. (1992). Trailing the dovetail shuffle to its lair.
    The Annals of Applied Probability, Vol. 2, No. 2, 294-313.
    """
    cut_point = np.random.binomial(len(deck), 0.5)
    return Deck(deck[cut_point:] + deck[:cut_point])

sequence(steps)

Chains individual shuffles into a sequence of shuffles.

Example:

from shuffl.models import gsr, strip, cut sequence
from shuffl import Deck

# Create a deck of 52 cards
deck = Deck(range(1,53))

# Define riffle, riffle, strip, riffle, cut sequence
shuffle = sequence([gsr, gsr, strip, gsr, cut])

# Apply the shuffle
shuffled_deck = shuffle(deck)

# Print the shuffled deck
print(shuffled_deck)
PARAMETER DESCRIPTION
steps

List of shuffle models

TYPE: list[Shuffle]

RETURNS DESCRIPTION
Shuffle

Sequence of composed shuffle models

Source code in shuffl/models/_sequence.py
def sequence(
    steps: Annotated[list[Shuffle], Doc("List of shuffle models")],
) -> Annotated[Shuffle, Doc("Sequence of composed shuffle models")]:
    """Chains individual shuffles into a sequence of shuffles.

    **Example:**

    ```python
    from shuffl.models import gsr, strip, cut sequence
    from shuffl import Deck

    # Create a deck of 52 cards
    deck = Deck(range(1,53))

    # Define riffle, riffle, strip, riffle, cut sequence
    shuffle = sequence([gsr, gsr, strip, gsr, cut])

    # Apply the shuffle
    shuffled_deck = shuffle(deck)

    # Print the shuffled deck
    print(shuffled_deck)
    ```
    """

    def shuffle(deck: Deck) -> Deck:
        for step in steps:
            deck = step(deck)
        return deck

    return shuffle