Skip to content

Evaluate

shuffl.evaluate

This module provides different functions to evaluate shuffle models based on Monte-Carlo simulations.

The implemented functions include:

  • adjacent: Returns average number of adjacent pairs in a permutation
  • frequencies: Returns empirical probabilities
  • guess: Returns average number of correct guesses of the top card
  • risingseq: Returns average number of rising sequences in a permutation
  • solitaire: Returns probability of Player A winning at the game New Age Solitaire

adjacent(shuffle, num=1000)

Returns average number of adjacent pairs.

Adjacent pairs are pairs of cards that were together in the original deck and which are still together in the permutation.

Example:

from shuffl.evaluate import adjacent
from shuffl import Deck

# Deck in original order
deck = Deck(["A", "B", "C", "D", "E"])

# Permutation of deck
permutation = Deck(["B", "C", "A", "D", "E"])

# Print adjacent pairs
# [("B", "C"), ("D", "E")]
print(adjacent(permutation, deck))
PARAMETER DESCRIPTION
shuffle

A shuffle model

TYPE: Shuffle

num

Number of Monte-Carlo simulations

TYPE: int DEFAULT: 1000

RETURNS DESCRIPTION
list[list[float]]

Discrete probability density function for every card

Source code in shuffl/evaluate/_adjacent.py
def adjacent(
    shuffle: Annotated[Shuffle, Doc("A shuffle model")],
    num: Annotated[int, Doc("Number of Monte-Carlo simulations")] = 1000,
) -> Annotated[
    list[list[float]], Doc("Discrete probability density function for every card")
]:
    """Returns average number of adjacent pairs.

    Adjacent pairs are pairs of cards that were together in the original
    deck and which are still together in the permutation.

    **Example:**

    ```python
    from shuffl.evaluate import adjacent
    from shuffl import Deck

    # Deck in original order
    deck = Deck(["A", "B", "C", "D", "E"])

    # Permutation of deck
    permutation = Deck(["B", "C", "A", "D", "E"])

    # Print adjacent pairs
    # [("B", "C"), ("D", "E")]
    print(adjacent(permutation, deck))
    ```
    """
    deck = Deck(range(1, 53))

    return np.mean([len(adjacent_pairs(shuffle(deck), deck)) for _ in range(num)])

frequencies(shuffle, num=1000)

Computes the discrete probability density function resulting from applying the given shuffle to the given initial deck of cards via Monte-Carlo simulations.

Example:

from shuffl.models import gsr, sequence
from shuffl.evaluate import frequencies
from shuffl import Deck

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

# Creates a shuffle sequence of 6 riffle shuffles
# following the Gilbert-Shannon-Reeds model
shuffle = sequence([gsr]*6)

# Compute the discrete probability density function
# for all 52 cards via a Monte-Carlo simulation with
# 10000 iterations
proba = frequencies(shuffle, deck, 10000)

# Print the results for the initial top card
print(proba[0])
PARAMETER DESCRIPTION
shuffle

A shuffle model

TYPE: Shuffle

num

Number of Monte-Carlo simulations

TYPE: int DEFAULT: 1000

RETURNS DESCRIPTION
list[list[float]]

Discrete probability density function for every card

Source code in shuffl/evaluate/_frequencies.py
def frequencies(
    shuffle: Annotated[Shuffle, Doc("A shuffle model")],
    num: Annotated[int, Doc("Number of Monte-Carlo simulations")] = 1000,
) -> Annotated[
    list[list[float]], Doc("Discrete probability density function for every card")
]:
    """Computes the discrete probability density function resulting
    from applying the given shuffle to the given initial deck of cards via
    Monte-Carlo simulations.

    **Example:**

    ```python
    from shuffl.models import gsr, sequence
    from shuffl.evaluate import frequencies
    from shuffl import Deck

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

    # Creates a shuffle sequence of 6 riffle shuffles
    # following the Gilbert-Shannon-Reeds model
    shuffle = sequence([gsr]*6)

    # Compute the discrete probability density function
    # for all 52 cards via a Monte-Carlo simulation with
    # 10000 iterations
    proba = frequencies(shuffle, deck, 10000)

    # Print the results for the initial top card
    print(proba[0])
    ```
    """
    deck = Deck(range(1, 53))
    samples = [shuffle(deck) for _ in range(0, num)]

    return [
        [sum([i == e.index(card) for e in samples]) / num for i in range(len(deck))]
        for card in deck
    ]

solitaire(shuffle, num=1000)

Probability of Player A winning at the game New Age Solitaire determined via Monte-Carlo simulations.

Example:

from shuffl.evaluate import solitaire
from shuffl import Deck
from shuffl.models import sequence, gsr

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

# Create a shuffle model
shuffle = sequence([gsr]*10)

# Evaluate the probability of player A
# winning. For a well-mixed deck the expected
# probability is 0.5
print(solitaire(shuffle, deck, 100000))
PARAMETER DESCRIPTION
shuffle

A shuffle model

TYPE: Shuffle

num

Number of Monte-Carlo simulations

TYPE: int DEFAULT: 1000

RETURNS DESCRIPTION
float

Probability of player A winning

Source code in shuffl/evaluate/_solitaire.py
def solitaire(
    shuffle: Annotated[Shuffle, Doc("A shuffle model")],
    num: Annotated[int, Doc("Number of Monte-Carlo simulations")] = 1000,
) -> Annotated[float, Doc("Probability of player A winning")]:
    """Probability of Player A winning at the game New Age Solitaire
    determined via Monte-Carlo simulations.

    **Example:**

    ```python
    from shuffl.evaluate import solitaire
    from shuffl import Deck
    from shuffl.models import sequence, gsr

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

    # Create a shuffle model
    shuffle = sequence([gsr]*10)

    # Evaluate the probability of player A
    # winning. For a well-mixed deck the expected
    # probability is 0.5
    print(solitaire(shuffle, deck, 100000))
    ```
    """
    deck = Deck(range(1, 53))
    return np.mean([_round(deck, shuffle) for _ in range(num)])

guess(shuffle, num=1000)

A guesser has to guess the top card of a face down shuffled deck of cards. After each guess the top card is revealed and then discared.

The expected number of guesses is about 4.5 for a well-shuffled deck. The guessing game can thus be used to compare different shuffles.

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
shuffle

A shuffle model

TYPE: Shuffle

num

Number of Monte-Carlo simulations

TYPE: int DEFAULT: 1000

RETURNS DESCRIPTION
float

Average number of correct guesses

Source code in shuffl/evaluate/_guessing.py
def guess(
    shuffle: Annotated[Shuffle, Doc("A shuffle model")],
    num: Annotated[int, Doc("Number of Monte-Carlo simulations")] = 1000,
) -> Annotated[float, Doc("Average number of correct guesses")]:
    """A guesser has to guess the top card of a face down
    shuffled deck of cards. After each guess the top card is revealed
    and then discared.

    The expected number of guesses is about 4.5 for a well-shuffled deck.
    The guessing game can thus be used to compare different shuffles.

    **References:**

    - Bayer D., Diaconis P. (1992). Trailing the dovetail shuffle to its lair.
    The Annals of Applied Probability, Vol. 2, No. 2, 294-313.
    """
    deck = Deck(range(1, 53))
    return np.mean([_round(deck, shuffle) for _ in range(num)])