Algoritmo de Gale & Shapley

Anuncio
TEORÍA DE ALGORITMOS 1 – 75.29
TRABAJO PRÁCTICO Nº: 1
INTEGRANTES
Padrón
84672
PARA USO DE LA CÁTEDRA
Primera entrega
Corrector
Observaciones
Segunda entrega
Corrector
Observaciones
Nombre y Apellido
Juan Martín Muñoz Facorro
Email
[email protected]
ÍNDICE
Enunciado ........................................................................................................................................................... 3
Ejemplo .......................................................................................................................................................... 3
Algoritmo de Gale & Shapley ......................................................................................................................... 3
Datos de entrada............................................................................................................................................ 4
Resolución .......................................................................................................................................................... 5
Backtracking ................................................................................................................................................... 5
Orden del algoritmo ................................................................................................................................... 5
Gale & Shapley ............................................................................................................................................... 6
Orden del algoritmo ................................................................................................................................... 6
Conclusiones ....................................................................................................................................................... 8
Apéndice A ......................................................................................................................................................... 9
Apéndice B ........................................................................................................................................................ 11
Apéndice C ........................................................................................................................................................ 13
2
ENUNCIADO
Ustedes han sido contratados como casamenteros de una comunidad muy cerrada, formada por N hombres
y N mujeres, todos solteros, y que deben casarse (todos) entre sí este año. Basarán su asignación en las
preferencias de cada uno (es decir que le pedirán a cada hombre que haga un ranking de todas las mujeres,
calificándolas de 1 a N, y de igual modo le pedirán a cada mujer que haga un ranking de todos los hombres).
Para mantener la buena fama de casamenteros que tienen (que los ha hecho muy solicitados por diversas
comunidades) deben evitar que los matrimonios se separen al poco tiempo. En particular quieren evitar
armar parejas inestables (decimos que estamos en una situación inestable si un hombre y una mujer que
están casados con otros preferirían estar casados entre sí).
El problema de armar las parejas sin que haya una situación inestable se conoce como el problema de los
matrimonios estables. Trabajaremos con los siguientes conceptos:


Un par hombre-mujer es un par bloqueante de la asignación si están en pareja con otros cuando
preferirían estar en pareja entre sí.
Una asignación es estable si no contiene ningún par bloqueante (y es inestable si contiene alguno).
EJEMPLO
Hombres
Mujeres
a
b
c
d
J
K
L
M
1°
J
M
M
K
a
d
a
c
2°
K
L
L
J
c
b
d
d
3°
L
J
J
L
b
c
b
a
4°
M
K
K
M
d
a
c
b
Figura 1: Preferencias de hombres y mujeres
Si se asignara (a, L), (b, J), (c, M), (d, K) entonces (a, J) resultaría un par bloqueante (y por lo tanto (a, L), (b,
J), (c, M), (d, K) resultaría una asignación inestable, en la cual a y J terminarían separándose de sus
respectivas parejas para casarse entre sí, ya que cada uno de ellos estaría casado con otro/a pese a que a
eligió a J en primer lugar y J eligió a a en primer lugar. En cambio (a, J), (b, L), (c, M), (d, K) es una asignación
estable. Una manera de realizar una asignación estable es por backtracking. Sin embargo, existe un
algoritmo (de Gale & Shapley, 1962) que es más eficiente, ya que tiene orden polinomial en la cantidad de
personas.
ALGORITMO DE GALE & SHAPLEY
El algoritmo procede por rondas:

En la primera ronda cada hombre se le declara a la mujer que pre_ere independientemente de que
algún otro se le haya declarado. Entre todas las propuestas que recibió, cada mujer elige al hombre
3


mejor posicionado en su ranking y se compromete con él. Si una mujer no recibe ninguna
propuesta, espera hasta la próxima ronda.
En cada ronda subsiguiente los hombres que ya estén comprometidos no hacen nada. Cada hombre
no comprometido se le declara a la mujer mejor posicionada en su ranking que aún no lo rechazó,
independientemente de que ella esté comprometida o no. Cuando le toca el turno a las mujeres,
cada mujer acepta la propuesta del hombre mejor posicionado en su ranking (incluso puede llegar a
romper un compromiso; también puede suceder que su novio actual esté mejor posicionado que
todos sus nuevos pretendientes, en cuyo caso se queda con el novio actual). Si una mujer no recibe
ninguna propuesta, espera hasta la próxima ronda.
Mientras queden hombres no comprometidos al final de una ronda, se hace una nueva ronda.
Se pide:
1.
2.
Resolver el problema por backtracking.
a. Calcular el orden.
Programar el algoritmo de Gale & Shapley para resolver el problema.
a. Elegir las estructuras de datos adecuadas para implantar eficientemente el algoritmo y
calcular el orden. Justificar.
b. Justificar que la asignación es completa y estable, es decir que el algoritmo no deja
personas solteras y la asignación realizada es estable.
c. Justificar que el algoritmo termina siempre.
d. ¿El algoritmo es simétrico? Justificar.
e. Si se les permitiera a las mujeres cambiar la lista de preferencia durante la ejecución
del algoritmo, como podría hacer una mujer dada, para conseguir el hombre óptimo
(Pista: podría mentir en su lista de preferencias, hasta conseguir que el hombre
óptimo se le declare).
f. Explicar de qué estrategia algorítmica se trata. Justificar.
DATOS DE ENTRADA
El programa deberá recibir por la línea de comando el nombre de un archivo de texto con el siguiente
formato:
Alberto: Ana,Betina,Carla,Dalma
Bato: Dalma,Carla,Betina,Ana
Carlos: Dalma,Carla,Betina,Ana
Demian: Betina,Ana,Carla,Dalma
[línea en blanco]
Ana: Alberto,Carlos,Bato,Demian
Betina: Demian,Bato,Carlos,Alberto
Carla: Alberto,Demian,Bato,Carlos
Dalma: Carlos,Demian,Alberto,Bato
Donde la primera persona que aparece en la lista de cada participante es la más preferida y así
sucesivamente hasta llegar a la menos preferida en último lugar.
4
RESOLUCIÓN
BACKTRACKING
La solución por medio de este método recorre todas las combinaciones de parejas posibles, evaluando si la
asignación de parejas encontrada es estable, si lo es, se encontró una posible solución, si no lo es, se sigue
formando las parejas aún no combinadas.
Para la implementación del algoritmo se precisa saber qué parejas se han formado así como también qué
hombres y qué mujeres ya tienen una pareja asociada. También se debe realizar, con la creación de cada
nueva pareja, la verificación de que hasta el momento la solución es estable, dado que no tiene sentido
seguir formando parejas si un par de ellas presenta una inestabilidad.
La lista de parejas de la solución se implementó con una lista doble, más específicamente, la estructura de
datos collections.deque de python. Los acceso al principio y fin de la lista son de orden O(1)1. Para
mantener la lista de hombres se utilizó la misma estructura antes mencionada, con la diferencia que su
utilización fue sólo a modo de pila. La lista de mujeres se implementó con una lista de python, la cual es en
realidad un arreglo que se redimensiona según la cantidad de ítems que contiene. 2
Para lograr un orden constante al determinar si una persona prefiere a otra, cada una de ellas tiene una
tabla de hash con los nombres del sexo opuesto como clave y la preferencia como valor. La estructura
utilizada para el hash es la obtenida por medio de la función dict, la cual tiene complejidad promedio O(1) al
agregar o acceder a un elemento.
En el Apéndice A se puede encontrar el código fuente de la clase Person utilizada para la resolución tanto
por backtracking como por el agoritmos de Gale y Shapley. El Apéndice B contiene el código específico para
la resolución por el método de backtracking, es decir, la clase Solution y Backtracking.
ORDEN DEL ALGORITMO
Dado que este algoritmo prueba todas las combinaciones de parejas posibles se puede pensar el recorrido
del espacio de soluciones como el representado por el siguiente árbol:
1 Time Complexity - http://wiki.python.org/moin/TimeComplexity
2 Python list implementation - http://www.laurentluce.com/posts/python-list-implementation/
5
Siguiendo este árbol puede determinarse que si en cada rama se tienen en cuenta solo las mujeres solteras
para cada hombre se probarán combinaciones del orden de O(n!).
Dado que en el algoritmo implementado se recorren todas las mujeres para buscar la primera soltera, el
algoritmo es en realidad de orden O(nn), lo cual a fines prácticos es tan desventajoso como la función
factorial.
GALE & SHAPLEY
El algoritmo de esta sección no necesita mantener la lista de pares encontrados, dado que a medida que se
van formando y modificando las parejas, la persona con la que quede finalmente comprometida será la
definitiva.
Para mantener la lista de hombres solteros se utiliza la lista doble collections.deque. La lista de preferencia
para cada persona se carga en una tabla de hash de la misma forma que en el algoritmo por backtracking.
Dado que se debe acceder a cada mujer según la preferencia de cada hombre dependiendo del orden de
cada hombre, la lista de mujeres se implementó con una tabla de hash, con lo cual se puede acceder por
nombre a cada una de ellas con orden O(1).
ORDEN DEL ALGORITMO
Considerando que cada hombre en el peor de los casos se le declara a cada mujer de su lista de
preferencias, la complejidad del algoritmo de Gale y Shapley es O(n2).
El código fuente de la implementación del algoritmo se puede encontrar en el Apéndice C.
Asignación Completa y Estable
Para probar que ningún hombre o mujer queda sin pareja, podemos plantear que si al final de la corrida del
algoritmo un hombre se le declaró a cada mujer de su lista y sigue soltero, entonces cada una de esas
mujeres prefirió a otro hombre antes que a él, por lo cual cada una de ellas debería estar en pareja. Como
hay tantas mujeres como hombres esto es imposible, por lo que se puede concluir que todo hombre al final
del algoritmo tiene pareja.
La estabilidad de la asignación surge del siguiente planteo: la asignación es inestable si al finalizar el
algoritmo dado un hombre m comprometido con una mujer w, y otro hombre m’ comprometido con otra
mujer w’; m prefiere a w’ antes que a w y w’ prefiera a m antes que a m’. Si ocurre esto, significa que m se
le tiene que haber declarado antes a w’ que a w, dado que se encuentra antes en la lista de preferencia,
pero si ocurrió esto, y w’ prefiera a m, entonces nunca podría haber abandonado a m por m’. Concluimos
entonces que la inestabilidad planteada no puede existir.
El Algoritmo Termina Siempre
Como consecuencia de lo expuesto en el punto anterior (ningún hombre queda sin pareja), es válido afirmar
que el algoritmo termina, dado que si ningún hombre queda sin pareja, lo mismo pasa con las mujeres.
Simetría
6
El algoritmo de Gale y Shapley tiene la característica que para el género que se declara al otro, la persona
con la que se compromete, si esta cambia durante la corrida, va decreciendo en el orden de preferencia.
Mientras que para el género al cual se le propone, la persona con la que se va comprometiendo, se
encuentra cada vez más arriba de su lista de preferencia. Por lo descrito anteriormente, el algoritmo no es
simétrico ya que la situación de los dos géneros no es equivalente.
Por ejemplo, si los hombres son los que se declaran, terminarán comprometidos con la mejor mujer posible
que no los rechazó o abandonó por otro, mientras que las mujeres quedarán comprometidas con el mejor
hombre que se les declaró.
Manipulación de Preferencias
Un miembro del género al que se le declaran, puede lograr obtener a la primera persona de su lista de
preferencias, mintiendo al respecto de esta misma, siguiendo la siguiente determinación cada vez que se le
declara una persona: aceptar cualquier declaración mientras que la pareja que tiene no sea la persona
óptima de su lista de preferencia.
Para probar que esto funciona, podemos suponer el caso natural (determinado por las preferencias de la
instancia del problema) en el cual a una persona se le declaran todas las personas del otro género. En este
caso, la persona recibe las propuestas de sus pretendientes de menor a mayor en relación a su preferencia,
pero finalmente terminará con la primera y óptima.
Ahora en vez de que la situación se dé naturalmente suponemos que la persona miente, conociendo la
mecánica de la selección de parejas. Esto no cambia el escenario planteado en el caso natural, dado que la
persona aceptará tantas personas como propuestas reciba, y en nuestro caso, sólo hasta que encuentre a la
persona que busca.
Estrategia Algorítmica
El algoritmo responde a una estrategia en la cual en cada iteración se trata de formar una pareja, teniendo
en cuenta sólo los atributos de dos elementos del conjunto, lo que demuestra una visión y un intento de
optimización pura y exclusivamente local. Cada iteración posterior trabajará de la misma forma, pero
teniendo en cuenta el escenario heredado de otras iteraciones, construyendo incrementalmente una
solución final.
Las características del algoritmo de Gale y Shapley mencionadas determinan que la estrategia utilizada es
greedy.
7
CONCLUSIONES
Luego de implementar los dos algoritmos presentes en este informe, se obtuvo una visión más detallada de
los diferentes aspectos a tener en cuenta al seleccionar las estructuras de datos a utilizar, así como la
necesidad de verificar el orden de las estructuras implementadas por terceros, para garantizar que la
complejidad que se busca pueda lograrse.
La diferencia de los órdenes entre los dos algoritmos analizados es abismal. El de Gale y Shapley, aunque no
sea simétrico y, como consecuencia, favorezca a uno u otro género, logra obtener una solución en tiempo
polinómico, lo cual es altamente deseable, sobre todo si la alternativa disponible, algoritmo de
backtracking, presenta un orden de tiempo exponencial.
8
APÉNDICE A
PERSON.PY
# -*- coding: utf-8 -*from collections import deque
class Person:
prefs = None
prefnames = deque()
fiancee = None
name = None
def __init__(self, name, preferences=[]):
"""Initializes the preferences hashtable.
O(n)"""
self.name = name
self.prefs = dict()
i = 0
for name in preferences.split(","):
name = name.strip()
self.prefs[name] = i
self.prefnames.appendleft(name)
i = i + 1
def prefers(self, p1):
"""Determins wheter this person prefers its current
fiancee or the one specified in the parameter.
O(1)"""
result = True
if self.fiancee is not None:
result = self.prefs[p1.name] > self.prefs[self.fiancee.name]
return result
def engage(self, p):
self.fiancee = p
p.fiancee = self
def break_up(self):
if self.fiancee is not None:
self.fiancee.fiancee = None
self.fiancee = None
def get_prospect(self):
if len(self.prefnames) > 0:
return self.prefnames.pop()
return None
9
MAIN.PY
# -*- coding: utf-8 -*###############################################################################
# Import Modules
###############################################################################
import sys
from backtracking import backtracking
from galeshapley import galeshapley
from collections import deque
filename = sys.argv[1]
print "------------------------------------"
print "Backtracking"
b = backtracking.Backtracking(filename)
b.match()
print "------------------------------------"
print "Gale & Shapley"
print "---------------------"
gs = galeshapley.GaleShapley(filename)
gs.match()
10
APÉNDICE B
SOLUTION.PY
# -*- coding: utf-8 -*from collections import deque
class Solution:
__pairs = None
def __init__(self):
self.__pairs = deque()
def is_stable(self, pair):
for p in self.__pairs:
m1 = p[0]
w1 = p[1]
m2 = pair[0]
w2 = pair[1]
if ((m1.prefers(w2) and w2.prefers(m1))
or (m2.prefers(w1) and w1.prefers(m2))):
return False
return True
def push(self, pair):
self.__pairs.append(pair)
def pop(self):
pair = self.__pairs.pop()
return pair
def show(self):
print "----------------------"
for p in self.__pairs:
print "(", p[0].name, ", ", p[1].name, ")"
BACKTRACKING.PY
# -*- coding: utf-8 -*from collections import deque
from model.person import Person
from model.solution import Solution
class Backtracking:
men = deque()
women = []
solution = Solution()
def __init__(self, filename):
self.load_data(filename)
def load_data(self, filename):
"""Loads men and women [O(n)] and their preference lists [O(n)]
O(n^2)"""
file = open(filename)
genre = 'Male'
for line in file:
words = line.split(":")
if line == '\n':
genre = 'Female'
else:
11
name = words[0]
preferences = words[1]
person = Person(name, preferences)
if genre == 'Male':
self.men.append(person)
else:
self.women.append(person)
file.close()
def match(self):
"""Finds all stable matchings
O(n^n)"""
# If there are still
if len(self.men) != 0:
#Take the first man in the list
m = self.men.pop()
#Check for women without commitment
for w in self.women:
if w.fiancee is None:
#Build pair
pair = [m, w]
m.engage(w)
#Verify that new pair doesn't create instability
if self.solution.is_stable(pair):
self.solution.push(pair)
self.match()
self.solution.pop()
m.break_up()
# Get the man back in the stack
self.men.append(m)
else:
self.solution.show() # Solution found
12
APÉNDICE C
GALESHAPLEY.PY
# -*- coding: utf-8 -*from collections import deque
from model.person import Person
from model.solution import Solution
class GaleShapley:
singles = deque()
men = []
women = dict()
def __init__(self, filename):
self.load_data(filename)
def load_data(self, filename):
"""Loads men and women [O(n)] and their preference lists [O(n)]
O(n^2)"""
file = open(filename)
genre = 'Male'
for line in file:
words = line.split(":")
if line == '\n':
genre = 'Female'
else:
name = words[0]
preferences = words[1]
person = Person(name, preferences)
if genre == 'Male':
self.men.append(person)
else:
self.women[name] = person
file.close()
self.singles = deque(self.men)
def match(self):
"""Finds a stable matching in O(n^2)"""
# If there are still single men
while len(self.singles) != 0:
#Take a single man
m = self.singles.pop()
#Get next woman's name in the preference list
name = m.get_prospect()
if name is None:
raise Exception("This shouldn't be happening!")
#Get woman by name
w = self.women[name]
#Check who the woman prefers
if w.prefers(m):
w.break_up()
m.engage(w)
else:
self.singles.appendleft(m)
for m in self.men:
print "(", m.name, ",", m.fiancee.name, ")"
13
Descargar