Matching games - Game Theory

Skip to content
Back to top
View this page
Edit this page

# Matching games

This module implements a class for matching games (stable marriage problems) [DI1989]. At present the extended Gale-Shapley algorithm is implemented which can be used to obtain stable matchings.

AUTHORS:

- James Campbell and Vince Knight 06-2014: Original version

class sage.game_theory.matching_game.MatchingGame(generator, revr=None)

  Bases: `SageObject`

  A matching game.

  A matching game (also called a stable matching problem) models a situation in a population of \(N\) suitors and \(N\) reviewers. Suitors and reviewers rank their preferences and attempt to find a match.

  Formally, a matching game of size \(N\) is defined by two disjoint sets \(S\) and \(R\) of size \(N\). Associated to each element of \(S\) and \(R\) is a preference list:

  \[f : S \to R^N \text{ and } g : R \to S^N.\]

  Here is an example of matching game on 4 players:

  \[\begin{split}S = \{J, K, L, M\}, \\ R = \{A, B, C, D\}.\end{split}\]

  With preference functions:

  \[ \begin{align}\begin{aligned}\begin{split}f(s) = \begin{cases} (A, D, C, B) & \text{ if } s=J,\\ (A, B, C, D) & \text{ if } s=K,\\ (B, D, C, A) & \text{ if } s=L,\\ (C, A, B, D) & \text{ if } s=M,\\ \end{cases}\end{split}\\\begin{split}g(s) = \begin{cases} (L, J, K, M) & \text{ if } s=A,\\ (J, M, L, K) & \text{ if } s=B,\\ (K, M, L, J) & \text{ if } s=C,\\ (M, K, J, L) & \text{ if } s=D.\\ \end{cases}\end{split}\end{aligned}\end{align} \]

  INPUT:

  Two potential inputs are accepted (see below to see the effect of each):

  - `reviewer/suitors_preferences` – dictionary containing the preferences of all players:

    - key - each reviewer/suitors

    - value - a tuple of suitors/reviewers

  OR:

  - `integer` – integer simply representing the number of reviewers and suitors

  To implement the above game in Sage:

  Sage

      sage: suitr_pref = {'J': ('A', 'D', 'C', 'B'),
      ....:               'K': ('A', 'B', 'C', 'D'),
      ....:               'L': ('B', 'D', 'C', 'A'),
      ....:               'M': ('C', 'A', 'B', 'D')}
      sage: reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
      ....:                 'B': ('J', 'M', 'L', 'K'),
      ....:                 'C': ('K', 'M', 'L', 'J'),
      ....:                 'D': ('M', 'K', 'J', 'L')}
      sage: m = MatchingGame([suitr_pref, reviewr_pref])
      sage: m
      A matching game with 4 suitors and 4 reviewers
      sage: m.suitors()
      ('J', 'K', 'L', 'M')
      sage: m.reviewers()
      ('A', 'B', 'C', 'D')

  Python

      >>> from sage.all import *
      >>> suitr_pref = {'J': ('A', 'D', 'C', 'B'),
      ...               'K': ('A', 'B', 'C', 'D'),
      ...               'L': ('B', 'D', 'C', 'A'),
      ...               'M': ('C', 'A', 'B', 'D')}
      >>> reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
      ...                 'B': ('J', 'M', 'L', 'K'),
      ...                 'C': ('K', 'M', 'L', 'J'),
      ...                 'D': ('M', 'K', 'J', 'L')}
      >>> m = MatchingGame([suitr_pref, reviewr_pref])
      >>> m
      A matching game with 4 suitors and 4 reviewers
      >>> m.suitors()
      ('J', 'K', 'L', 'M')
      >>> m.reviewers()
      ('A', 'B', 'C', 'D')

  A matching \(M\) is any bijection between \(S\) and \(R\). If \(s \in S\) and \(r \in R\) are matched by \(M\) we denote:

  \[M(s) = r.\]

  On any given matching game, one intends to find a matching that is stable. In other words, so that no one individual has an incentive to break their current match.

  Formally, a stable matching is a matching that has no blocking pairs. A blocking pair is any pair \((s, r)\) such that \(M(s) \neq r\) but \(s\) prefers \(r\) to \(M(r)\) and \(r\) prefers \(s\) to \(M^{-1}(r)\).

  To obtain the stable matching in Sage we use the `solve` method which uses the extended Gale-Shapley algorithm [DI1989]:

  Sage

      sage: m.solve()
      {'J': 'A', 'K': 'C', 'L': 'D', 'M': 'B'}

  [Python]

      >>> from sage.all import *
      >>> m.solve()
      {'J': 'A', 'K': 'C', 'L': 'D', 'M': 'B'}

  Matchings have a natural representations as bipartite graphs:

  Sage

      sage: plot(m)                                                                   # needs sage.plot
      Graphics object consisting of 13 graphics primitives

  Python

      >>> from sage.all import *
      >>> plot(m)                                                                   # needs sage.plot
      Graphics object consisting of 13 graphics primitives

  The above plots the bipartite graph associated with the matching. This plot can be accessed directly:

  Sage

      sage: graph = m.bipartite_graph()
      sage: graph
      Bipartite graph on 8 vertices

  [Python]

      >>> from sage.all import *
      >>> graph = m.bipartite_graph()
      >>> graph
      Bipartite graph on 8 vertices

  It is possible to initiate a matching game without having to name each suitor and reviewer:

  Sage

      sage: n = 8
      sage: big_game = MatchingGame(n)
      sage: big_game.suitors()
      (1, 2, 3, 4, 5, 6, 7, 8)
      sage: big_game.reviewers()
      (-1, -2, -3, -4, -5, -6, -7, -8)

  Python

      >>> from sage.all import *
      >>> n = Integer(8)
      >>> big_game = MatchingGame(n)
      >>> big_game.suitors()
      (1, 2, 3, 4, 5, 6, 7, 8)
      >>> big_game.reviewers()
      (-1, -2, -3, -4, -5, -6, -7, -8)

  If we attempt to obtain the stable matching for the above game, without defining the preference function we obtain an error:

  Sage

      sage: big_game.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  [Python]

      >>> from sage.all import *
      >>> big_game.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  To continue we have to populate the preference dictionary. Here is one example where the preferences are simply the corresponding element of the permutation group:

  Sage

      sage: from itertools import permutations
      sage: suitr_preferences = list(permutations([-i-1 for i in range(n)]))
      sage: revr_preferences = list(permutations([i+1 for i in range(n)]))
      sage: for player in range(n):
      ....:     big_game.suitors()[player].pref = suitr_preferences[player]
      ....:     big_game.reviewers()[player].pref = revr_preferences[-player]
      sage: big_game.solve()
      {1: -1, 2: -8, 3: -6, 4: -7, 5: -5, 6: -4, 7: -3, 8: -2}

  Python

      >>> from sage.all import *
      >>> from itertools import permutations
      >>> suitr_preferences = list(permutations([-i-Integer(1) for i in range(n)]))
      >>> revr_preferences = list(permutations([i+Integer(1) for i in range(n)]))
      >>> for player in range(n):
      ...     big_game.suitors()[player].pref = suitr_preferences[player]
      ...     big_game.reviewers()[player].pref = revr_preferences[-player]
      >>> big_game.solve()
      {1: -1, 2: -8, 3: -6, 4: -7, 5: -5, 6: -4, 7: -3, 8: -2}

  Note that we can also combine the two ways of creating a game. For example here is an initial matching game:

  Sage

      sage: suitrs = {'Romeo': ('Juliet', 'Rosaline'),
      ....:            'Mercutio': ('Juliet', 'Rosaline')}
      sage: revwrs = {'Juliet': ('Romeo', 'Mercutio'),
      ....:           'Rosaline': ('Mercutio', 'Romeo')}
      sage: g = MatchingGame(suitrs, revwrs)

  [Python]

      >>> from sage.all import *
      >>> suitrs = {'Romeo': ('Juliet', 'Rosaline'),
      ...            'Mercutio': ('Juliet', 'Rosaline')}
      >>> revwrs = {'Juliet': ('Romeo', 'Mercutio'),
      ...           'Rosaline': ('Mercutio', 'Romeo')}
      >>> g = MatchingGame(suitrs, revwrs)

  Let us assume that all of a sudden a new pair of suitors and reviewers is added but their names are not known:

  Sage

      sage: g.add_reviewer()
      sage: g.add_suitor()
      sage: g.reviewers()
      (-3, 'Juliet', 'Rosaline')
      sage: g.suitors()
      (3, 'Mercutio', 'Romeo')

  Python

      >>> from sage.all import *
      >>> g.add_reviewer()
      >>> g.add_suitor()
      >>> g.reviewers()
      (-3, 'Juliet', 'Rosaline')
      >>> g.suitors()
      (3, 'Mercutio', 'Romeo')

  Note that when adding a reviewer or a suitor all preferences are wiped:

  Sage

      sage: [s.pref for s in g.suitors()]
      [[], [], []]
      sage: [r.pref for r in g.reviewers()]
      [[], [], []]

  [Python]

      >>> from sage.all import *
      >>> [s.pref for s in g.suitors()]
      [[], [], []]
      >>> [r.pref for r in g.reviewers()]
      [[], [], []]

  If we now try to solve the game we will get an error as we have not specified the preferences which will need to be updated:

  Sage

      sage: g.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  Python

      >>> from sage.all import *
      >>> g.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  Here we update the preferences so that the new reviewers and suitors do not affect things too much (they prefer each other and are the least preferred of the others):

  Sage

      sage: g.suitors()[1].pref = suitrs['Mercutio'] + (-3,)
      sage: g.suitors()[2].pref = suitrs['Romeo'] + (-3,)
      sage: g.suitors()[0].pref = (-3, 'Juliet', 'Rosaline')
      sage: g.reviewers()[2].pref = revwrs['Rosaline'] + (3,)
      sage: g.reviewers()[1].pref = revwrs['Juliet'] + (3,)
      sage: g.reviewers()[0].pref = (3, 'Romeo', 'Mercutio')

  [Python]

      >>> from sage.all import *
      >>> g.suitors()[Integer(1)].pref = suitrs['Mercutio'] + (-Integer(3),)
      >>> g.suitors()[Integer(2)].pref = suitrs['Romeo'] + (-Integer(3),)
      >>> g.suitors()[Integer(0)].pref = (-Integer(3), 'Juliet', 'Rosaline')
      >>> g.reviewers()[Integer(2)].pref = revwrs['Rosaline'] + (Integer(3),)
      >>> g.reviewers()[Integer(1)].pref = revwrs['Juliet'] + (Integer(3),)
      >>> g.reviewers()[Integer(0)].pref = (Integer(3), 'Romeo', 'Mercutio')

  Now the game can be solved:

  Sage

      sage: D = g.solve()
      sage: D['Mercutio']
      'Rosaline'
      sage: D['Romeo']
      'Juliet'
      sage: D[3]
      -3

  Python

      >>> from sage.all import *
      >>> D = g.solve()
      >>> D['Mercutio']
      'Rosaline'
      >>> D['Romeo']
      'Juliet'
      >>> D[Integer(3)]
      -3

  Note that the above could be equivalently (and more simply) carried out by simply updated the original preference dictionaries:

  Sage

      sage: for key in suitrs:
      ....:     suitrs[key] = suitrs[key] + (-3,)
      sage: for key in revwrs:
      ....:     revwrs[key] = revwrs[key] + (3,)
      sage: suitrs[3] = (-3, 'Juliet', 'Rosaline')
      sage: revwrs[-3] = (3, 'Romeo', 'Mercutio')
      sage: g = MatchingGame(suitrs, revwrs)
      sage: D = g.solve()
      sage: D['Mercutio']
      'Rosaline'
      sage: D['Romeo']
      'Juliet'
      sage: D[3]
      -3

  [Python]

      >>> from sage.all import *
      >>> for key in suitrs:
      ...     suitrs[key] = suitrs[key] + (-Integer(3),)
      >>> for key in revwrs:
      ...     revwrs[key] = revwrs[key] + (Integer(3),)
      >>> suitrs[Integer(3)] = (-Integer(3), 'Juliet', 'Rosaline')
      >>> revwrs[-Integer(3)] = (Integer(3), 'Romeo', 'Mercutio')
      >>> g = MatchingGame(suitrs, revwrs)
      >>> D = g.solve()
      >>> D['Mercutio']
      'Rosaline'
      >>> D['Romeo']
      'Juliet'
      >>> D[Integer(3)]
      -3

  It can be shown that the Gale-Shapley algorithm will return the stable matching that is optimal from the point of view of the suitors and is in fact the worst possible matching from the point of view of the reviewers. To quickly obtain the matching that is optimal for the reviewers we use the `solve` method with the `invert=True` option:

  Sage

      sage: left_dict = {'a': ('A', 'B', 'C'),
      ....:              'b': ('B', 'C', 'A'),
      ....:              'c': ('B', 'A', 'C')}
      sage: right_dict = {'A': ('b', 'c', 'a'),
      ....:               'B': ('a', 'c', 'b'),
      ....:               'C': ('a', 'b', 'c')}
      sage: quick_game = MatchingGame([left_dict, right_dict])
      sage: quick_game.solve()
      {'a': 'A', 'b': 'C', 'c': 'B'}
      sage: quick_game.solve(invert=True)
      {'A': 'c', 'B': 'a', 'C': 'b'}

  Python

      >>> from sage.all import *
      >>> left_dict = {'a': ('A', 'B', 'C'),
      ...              'b': ('B', 'C', 'A'),
      ...              'c': ('B', 'A', 'C')}
      >>> right_dict = {'A': ('b', 'c', 'a'),
      ...               'B': ('a', 'c', 'b'),
      ...               'C': ('a', 'b', 'c')}
      >>> quick_game = MatchingGame([left_dict, right_dict])
      >>> quick_game.solve()
      {'a': 'A', 'b': 'C', 'c': 'B'}
      >>> quick_game.solve(invert=True)
      {'A': 'c', 'B': 'a', 'C': 'b'}

  EXAMPLES:

  8 player letter game:

  Sage

      sage: suitr_pref = {'J': ('A', 'D', 'C', 'B'),
      ....:               'K': ('A', 'B', 'C', 'D'),
      ....:               'L': ('B', 'D', 'C', 'A'),
      ....:               'M': ('C', 'A', 'B', 'D')}
      sage: reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
      ....:                 'B': ('J', 'M', 'L', 'K'),
      ....:                 'C': ('K', 'M', 'L', 'J'),
      ....:                 'D': ('M', 'K', 'J', 'L')}
      sage: m = MatchingGame([suitr_pref, reviewr_pref])
      sage: m.suitors()
      ('J', 'K', 'L', 'M')
      sage: m.reviewers()
      ('A', 'B', 'C', 'D')

  [Python]

      >>> from sage.all import *
      >>> suitr_pref = {'J': ('A', 'D', 'C', 'B'),
      ...               'K': ('A', 'B', 'C', 'D'),
      ...               'L': ('B', 'D', 'C', 'A'),
      ...               'M': ('C', 'A', 'B', 'D')}
      >>> reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
      ...                 'B': ('J', 'M', 'L', 'K'),
      ...                 'C': ('K', 'M', 'L', 'J'),
      ...                 'D': ('M', 'K', 'J', 'L')}
      >>> m = MatchingGame([suitr_pref, reviewr_pref])
      >>> m.suitors()
      ('J', 'K', 'L', 'M')
      >>> m.reviewers()
      ('A', 'B', 'C', 'D')

  Also works for numbers:

  Sage

      sage: suit = {0: (3, 4),
      ....:         1: (3, 4)}
      sage: revr = {3: (0, 1),
      ....:         4: (1, 0)}
      sage: g = MatchingGame([suit, revr])

  Python

      >>> from sage.all import *
      >>> suit = {Integer(0): (Integer(3), Integer(4)),
      ...         Integer(1): (Integer(3), Integer(4))}
      >>> revr = {Integer(3): (Integer(0), Integer(1)),
      ...         Integer(4): (Integer(1), Integer(0))}
      >>> g = MatchingGame([suit, revr])

  Can create a game from an integer. This gives default set of preference functions:

  Sage

      sage: g = MatchingGame(3)
      sage: g
      A matching game with 3 suitors and 3 reviewers

  [Python]

      >>> from sage.all import *
      >>> g = MatchingGame(Integer(3))
      >>> g
      A matching game with 3 suitors and 3 reviewers

  We have an empty set of preferences for a default named set of preferences:

  Sage

      sage: for s in g.suitors():
      ....:     s, s.pref
      (1, [])
      (2, [])
      (3, [])
      sage: for r in g.reviewers():
      ....:     r, r.pref
      (-1, [])
      (-2, [])
      (-3, [])

  Python

      >>> from sage.all import *
      >>> for s in g.suitors():
      ...     s, s.pref
      (1, [])
      (2, [])
      (3, [])
      >>> for r in g.reviewers():
      ...     r, r.pref
      (-1, [])
      (-2, [])
      (-3, [])

  Before trying to solve such a game the algorithm will check if it is complete or not:

  Sage

      sage: g.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  [Python]

      >>> from sage.all import *
      >>> g.solve()
      Traceback (most recent call last):
      ...
      ValueError: suitor preferences are not complete

  To be able to obtain the stable matching we must input the preferences:

  Sage

      sage: for s in g.suitors():
      ....:   s.pref = (-1, -2, -3)
      sage: for r in g.reviewers():
      ....:   r.pref = (1, 2, 3)
      sage: g.solve()
      {1: -1, 2: -2, 3: -3}

  Python

      >>> from sage.all import *
      >>> for s in g.suitors():
      ...   s.pref = (-Integer(1), -Integer(2), -Integer(3))
      >>> for r in g.reviewers():
      ...   r.pref = (Integer(1), Integer(2), Integer(3))
      >>> g.solve()
      {1: -1, 2: -2, 3: -3}

  add_reviewer(name=None)

    Add a reviewer to the game.

    INPUT:

    - `name` – can be a string or number; if left blank will automatically generate an integer

    EXAMPLES:

    Creating a two player game:

    Sage

        sage: g = MatchingGame(2)
        sage: g.reviewers()
        (-1, -2)

    Python

        >>> from sage.all import *
        >>> g = MatchingGame(Integer(2))
        >>> g.reviewers()
        (-1, -2)

    Adding a suitor without specifying a name:

    Sage

        sage: g.add_reviewer()
        sage: g.reviewers()
        (-1, -2, -3)

    [Python]

        >>> from sage.all import *
        >>> g.add_reviewer()
        >>> g.reviewers()
        (-1, -2, -3)

    Adding a suitor while specifying a name:

    Sage

        sage: g.add_reviewer(10)
        sage: g.reviewers()
        (-1, -2, -3, 10)

    Python

        >>> from sage.all import *
        >>> g.add_reviewer(Integer(10))
        >>> g.reviewers()
        (-1, -2, -3, 10)

    Note that now our game is no longer complete:

    Sage

        sage: g._is_complete()
        Traceback (most recent call last):
        ...
        ValueError: must have the same number of reviewers as suitors

    [Python]

        >>> from sage.all import *
        >>> g._is_complete()
        Traceback (most recent call last):
        ...
        ValueError: must have the same number of reviewers as suitors

    Note that an error is raised if one tries to add a reviewer with a name that already exists:

    Sage

        sage: g.add_reviewer(10)
        Traceback (most recent call last):
        ...
        ValueError: a reviewer with name "10" already exists

    Python

        >>> from sage.all import *
        >>> g.add_reviewer(Integer(10))
        Traceback (most recent call last):
        ...
        ValueError: a reviewer with name "10" already exists

    If we add a reviewer without passing a name then the name of the reviewer will not use one that is already chosen:

    Sage

        sage: suit = {0: (-1,  -3),
        ....:         1: (-3, -1)}
        sage: revr = {-1: (0, 1),
        ....:         -3: (1, 0)}
        sage: g = MatchingGame([suit, revr])
        sage: g.reviewers()
        (-1, -3)

        sage: g.add_reviewer()
        sage: g.reviewers()
        (-1, -3, -4)

    [Python]

        >>> from sage.all import *
        >>> suit = {Integer(0): (-Integer(1),  -Integer(3)),
        ...         Integer(1): (-Integer(3), -Integer(1))}
        >>> revr = {-Integer(1): (Integer(0), Integer(1)),
        ...         -Integer(3): (Integer(1), Integer(0))}
        >>> g = MatchingGame([suit, revr])
        >>> g.reviewers()
        (-1, -3)

        >>> g.add_reviewer()
        >>> g.reviewers()
        (-1, -3, -4)

  add_suitor(name=None)

    Add a suitor to the game.

    INPUT:

    - `name` – can be a string or a number; if left blank will automatically generate an integer

    EXAMPLES:

    Creating a two player game:

    Sage

        sage: g = MatchingGame(2)
        sage: g.suitors()
        (1, 2)

    Python

        >>> from sage.all import *
        >>> g = MatchingGame(Integer(2))
        >>> g.suitors()
        (1, 2)

    Adding a suitor without specifying a name:

    Sage

        sage: g.add_suitor()
        sage: g.suitors()
        (1, 2, 3)

    [Python]

        >>> from sage.all import *
        >>> g.add_suitor()
        >>> g.suitors()
        (1, 2, 3)

    Adding a suitor while specifying a name:

    Sage

        sage: g.add_suitor('D')
        sage: g.suitors()
        (1, 2, 3, 'D')

    Python

        >>> from sage.all import *
        >>> g.add_suitor('D')
        >>> g.suitors()
        (1, 2, 3, 'D')

    Note that now our game is no longer complete:

    Sage

        sage: g._is_complete()
        Traceback (most recent call last):
        ...
        ValueError: must have the same number of reviewers as suitors

    [Python]

        >>> from sage.all import *
        >>> g._is_complete()
        Traceback (most recent call last):
        ...
        ValueError: must have the same number of reviewers as suitors

    Note that an error is raised if one tries to add a suitor with a name that already exists:

    Sage

        sage: g.add_suitor('D')
        Traceback (most recent call last):
        ...
        ValueError: a suitor with name "D" already exists

    Python

        >>> from sage.all import *
        >>> g.add_suitor('D')
        Traceback (most recent call last):
        ...
        ValueError: a suitor with name "D" already exists

    If we add a suitor without passing a name then the name of the suitor will not use one that is already chosen:

    Sage

        sage: suit = {0: (-1,  -2),
        ....:         2: (-2, -1)}
        sage: revr = {-1: (0, 1),
        ....:         -2: (1, 0)}
        sage: g = MatchingGame([suit, revr])
        sage: g.suitors()
        (0, 2)

        sage: g.add_suitor()
        sage: g.suitors()
        (0, 2, 3)

    [Python]

        >>> from sage.all import *
        >>> suit = {Integer(0): (-Integer(1),  -Integer(2)),
        ...         Integer(2): (-Integer(2), -Integer(1))}
        >>> revr = {-Integer(1): (Integer(0), Integer(1)),
        ...         -Integer(2): (Integer(1), Integer(0))}
        >>> g = MatchingGame([suit, revr])
        >>> g.suitors()
        (0, 2)

        >>> g.add_suitor()
        >>> g.suitors()
        (0, 2, 3)

  bipartite_graph()

    Construct a `BipartiteGraph` Object of the game. This method is similar to the plot method. Note that the game must be solved for this to work.

    EXAMPLES:

    An error is returned if the game is not solved:

    Sage

        sage: suit = {0: (3, 4),
        ....:         1: (3, 4)}
        sage: revr = {3: (0, 1),
        ....:         4: (1, 0)}
        sage: g = MatchingGame([suit, revr])
        sage: g.bipartite_graph()
        Traceback (most recent call last):
        ...
        ValueError: game has not been solved yet

        sage: g.solve()
        {0: 3, 1: 4}
        sage: g.bipartite_graph()
        Bipartite graph on 4 vertices

    Python

        >>> from sage.all import *
        >>> suit = {Integer(0): (Integer(3), Integer(4)),
        ...         Integer(1): (Integer(3), Integer(4))}
        >>> revr = {Integer(3): (Integer(0), Integer(1)),
        ...         Integer(4): (Integer(1), Integer(0))}
        >>> g = MatchingGame([suit, revr])
        >>> g.bipartite_graph()
        Traceback (most recent call last):
        ...
        ValueError: game has not been solved yet

        >>> g.solve()
        {0: 3, 1: 4}
        >>> g.bipartite_graph()
        Bipartite graph on 4 vertices

  plot()

    Create the plot representing the stable matching for the game. Note that the game must be solved for this to work.

    EXAMPLES:

    An error is returned if the game is not solved:

    Sage

        sage: suit = {0: (3, 4),
        ....:         1: (3, 4)}
        sage: revr = {3: (0, 1),
        ....:         4: (1, 0)}
        sage: g = MatchingGame([suit, revr])
        sage: plot(g)                                                               # needs sage.plot
        Traceback (most recent call last):
        ...
        ValueError: game has not been solved yet

        sage: g.solve()
        {0: 3, 1: 4}
        sage: plot(g)                                                               # needs sage.plot
        Graphics object consisting of 7 graphics primitives

    Python

        >>> from sage.all import *
        >>> suit = {Integer(0): (Integer(3), Integer(4)),
        ...         Integer(1): (Integer(3), Integer(4))}
        >>> revr = {Integer(3): (Integer(0), Integer(1)),
        ...         Integer(4): (Integer(1), Integer(0))}
        >>> g = MatchingGame([suit, revr])
        >>> plot(g)                                                               # needs sage.plot
        Traceback (most recent call last):
        ...
        ValueError: game has not been solved yet

        >>> g.solve()
        {0: 3, 1: 4}
        >>> plot(g)                                                               # needs sage.plot
        Graphics object consisting of 7 graphics primitives

  reviewers()

    Return the reviewers of `self`.

    EXAMPLES:

    Sage

        sage: g = MatchingGame(2)
        sage: g.reviewers()
        (-1, -2)

    Python

        >>> from sage.all import *
        >>> g = MatchingGame(Integer(2))
        >>> g.reviewers()
        (-1, -2)

  solve(invert=False)

    Compute a stable matching for the game using the Gale-Shapley algorithm.

    EXAMPLES:

    Sage

        sage: suitr_pref = {'J': ('A', 'D', 'C', 'B'),
        ....:               'K': ('A', 'B', 'C', 'D'),
        ....:               'L': ('B', 'C', 'D', 'A'),
        ....:               'M': ('C', 'A', 'B', 'D')}
        sage: reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
        ....:                 'B': ('J', 'M', 'L', 'K'),
        ....:                 'C': ('M', 'K', 'L', 'J'),
        ....:                 'D': ('M', 'K', 'J', 'L')}
        sage: m = MatchingGame([suitr_pref, reviewr_pref])
        sage: m.solve()
        {'J': 'A', 'K': 'D', 'L': 'B', 'M': 'C'}

        sage: suitr_pref = {'J': ('A', 'D', 'C', 'B'),
        ....:               'K': ('A', 'B', 'C', 'D'),
        ....:               'L': ('B', 'C', 'D', 'A'),
        ....:               'M': ('C', 'A', 'B', 'D')}
        sage: reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
        ....:                 'B': ('J', 'M', 'L', 'K'),
        ....:                 'C': ('M', 'K', 'L', 'J'),
        ....:                 'D': ('M', 'K', 'J', 'L')}
        sage: m = MatchingGame([suitr_pref, reviewr_pref])
        sage: m.solve(invert=True)
        {'A': 'L', 'B': 'J', 'C': 'M', 'D': 'K'}

        sage: suitr_pref = {1: (-1,)}
        sage: reviewr_pref = {-1: (1,)}
        sage: m = MatchingGame([suitr_pref, reviewr_pref])
        sage: m.solve()
        {1: -1}

        sage: suitr_pref = {}
        sage: reviewr_pref = {}
        sage: m = MatchingGame([suitr_pref, reviewr_pref])
        sage: m.solve()
        {}

    Python

        >>> from sage.all import *
        >>> suitr_pref = {'J': ('A', 'D', 'C', 'B'),
        ...               'K': ('A', 'B', 'C', 'D'),
        ...               'L': ('B', 'C', 'D', 'A'),
        ...               'M': ('C', 'A', 'B', 'D')}
        >>> reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
        ...                 'B': ('J', 'M', 'L', 'K'),
        ...                 'C': ('M', 'K', 'L', 'J'),
        ...                 'D': ('M', 'K', 'J', 'L')}
        >>> m = MatchingGame([suitr_pref, reviewr_pref])
        >>> m.solve()
        {'J': 'A', 'K': 'D', 'L': 'B', 'M': 'C'}

        >>> suitr_pref = {'J': ('A', 'D', 'C', 'B'),
        ...               'K': ('A', 'B', 'C', 'D'),
        ...               'L': ('B', 'C', 'D', 'A'),
        ...               'M': ('C', 'A', 'B', 'D')}
        >>> reviewr_pref = {'A': ('L', 'J', 'K', 'M'),
        ...                 'B': ('J', 'M', 'L', 'K'),
        ...                 'C': ('M', 'K', 'L', 'J'),
        ...                 'D': ('M', 'K', 'J', 'L')}
        >>> m = MatchingGame([suitr_pref, reviewr_pref])
        >>> m.solve(invert=True)
        {'A': 'L', 'B': 'J', 'C': 'M', 'D': 'K'}

        >>> suitr_pref = {Integer(1): (-Integer(1),)}
        >>> reviewr_pref = {-Integer(1): (Integer(1),)}
        >>> m = MatchingGame([suitr_pref, reviewr_pref])
        >>> m.solve()
        {1: -1}

        >>> suitr_pref = {}
        >>> reviewr_pref = {}
        >>> m = MatchingGame([suitr_pref, reviewr_pref])
        >>> m.solve()
        {}

  suitors()

    Return the suitors of `self`.

    EXAMPLES:

    Sage

        sage: g = MatchingGame(2)
        sage: g.suitors()
        (1, 2)

    Python

        >>> from sage.all import *
        >>> g = MatchingGame(Integer(2))
        >>> g.suitors()
        (1, 2)

class sage.game_theory.matching_game.Player(name)

  Bases: `object`

  A class to act as a data holder for the players used of the matching games.

  These instances are used when initiating players and to keep track of whether or not partners have a preference.