diff --git a/decide/postproc/tests.py b/decide/postproc/tests.py index 6b20f5851f..1d84469ef5 100644 --- a/decide/postproc/tests.py +++ b/decide/postproc/tests.py @@ -68,3 +68,167 @@ def testHuntington(self): self.assertEqual(values, expected_result) + + + def testDHont1(self): #Fácil de comprobar manualmente + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 12000}, + {'option':'Option 2','number':2,'votes': 140000}, + {'option':'Option 3','number':3,'votes': 110000}, + {'option':'Option 4','number':4,'votes': 205000}, + {'option':'Option 5','number':5,'votes': 150000}, + {'option':'Option 6','number':6,'votes': 16000} + ], + 'numEscanos': 10 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 12000, 'postproc': 0}, + {'option':'Option 2','number':2,'votes': 140000, 'postproc': 2}, + {'option':'Option 3','number':3,'votes': 110000, 'postproc': 2}, + {'option':'Option 4','number':4,'votes': 205000, 'postproc': 4}, + {'option':'Option 5','number':5,'votes': 150000, 'postproc': 2}, + {'option':'Option 6','number':6,'votes': 16000, 'postproc': 0} + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) + + + def testDHont2(self): #Votos muy igualados + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 65000}, + {'option':'Option 2','number':2,'votes': 60000}, + {'option':'Option 3','number':3,'votes': 50000}, + {'option':'Option 4','number':4,'votes': 55000}, + {'option':'Option 5','number':5,'votes': 62000}, + {'option':'Option 6','number':6,'votes': 57000}, + ], + 'numEscanos': 10 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 65000,'postproc': 2}, + {'option':'Option 2','number':2,'votes': 60000,'postproc': 2}, + {'option':'Option 3','number':3,'votes': 50000,'postproc': 1}, + {'option':'Option 4','number':4,'votes': 55000,'postproc': 1}, + {'option':'Option 5','number':5,'votes': 62000,'postproc': 2}, + {'option':'Option 6','number':6,'votes': 57000,'postproc': 2}, + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) + + + def testDHont3(self): #Votos muy desiguales + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 65000}, + {'option':'Option 2','number':2,'votes': 30000}, + {'option':'Option 3','number':3,'votes': 1500}, + {'option':'Option 4','number':4,'votes': 4500}, + {'option':'Option 5','number':5,'votes': 2000}, + ], + 'numEscanos': 100 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 65000,'postproc': 65}, + {'option':'Option 2','number':2,'votes': 30000,'postproc': 29}, + {'option':'Option 3','number':3,'votes': 1500,'postproc': 1}, + {'option':'Option 4','number':4,'votes': 4500,'postproc': 4}, + {'option':'Option 5','number':5,'votes': 2000,'postproc': 1}, + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) + + + def testDHont4(self): #Votos iguales + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 50000}, + {'option':'Option 2','number':2,'votes': 50000}, + {'option':'Option 3','number':3,'votes': 50000} + ], + 'numEscanos': 300 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 50000,'postproc': 100}, + {'option':'Option 2','number':2,'votes': 50000,'postproc': 100}, + {'option':'Option 3','number':3,'votes': 50000,'postproc': 100} + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) + + + def testDHont5(self): #Votos muy elevados + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 150150150150150}, + {'option':'Option 2','number':2,'votes': 300300300300300}, + {'option':'Option 3','number':3,'votes': 200200200200200} + ], + 'numEscanos': 100 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 150150150150150,'postproc': 23}, + {'option':'Option 2','number':2,'votes': 300300300300300,'postproc': 46}, + {'option':'Option 3','number':3,'votes': 200200200200200,'postproc': 31} + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) + + + def testDHont6(self): #Escaños elevados + data = { + 'type': 'DHONT', + 'options': [ + {'option':'Option 1','number':1,'votes': 15000}, + {'option':'Option 2','number':2,'votes': 75000}, + {'option':'Option 3','number':3,'votes': 10000}, + {'option':'Option 4','number':4,'votes': 5000}, + {'option':'Option 5','number':5,'votes': 2500}, + ], + 'numEscanos': 900 + } + + expected_result = [ + {'option':'Option 1','number':1,'votes': 15000,'postproc': 126}, + {'option':'Option 2','number':2,'votes': 75000,'postproc': 630}, + {'option':'Option 3','number':3,'votes': 10000,'postproc': 83}, + {'option':'Option 4','number':4,'votes': 5000,'postproc': 41}, + {'option':'Option 5','number':5,'votes': 2500,'postproc': 20} + ] + + response = self.client.post('/postproc/', data, format='json') + self.assertEqual(response.status_code, 200) + + values = response.json() + self.assertEqual(values, expected_result) diff --git a/decide/postproc/views.py b/decide/postproc/views.py index 89104a6ee4..77196e7e79 100644 --- a/decide/postproc/views.py +++ b/decide/postproc/views.py @@ -86,9 +86,31 @@ def HuntingtonHill(self,options,numEscanyos): return Response(options) + def dHont(self, options, numEscanyos): + + #Añadimos un campo para el contador de escaños asignados a cada opción + for op in options: + op['postproc'] = 0 + + #Para cada escaño recorremos todas las opciones usando la fórmula de d'Hont: número de votos de esa opción/(número de escaños asignados a esa opción + 1) + for escano in range(0, numEscanyos): + #Lista de tamaño igual al número de opciones. Recuento al aplicar la fórmula a cada opción (ordenados en la misma forma) + recuento = [] + for op in options: + r = op['votes'] / (op['postproc']+1) + recuento.append(r) + + #Obtenemos el índice del máximo valor en la lista de recuento de votos (del ganador del escaño) + ganador = recuento.index(max(recuento)) + #En la posicion del ganador le sumamos 1 escaño + options[ganador]['postproc'] += 1 + + return Response(options) + + def post(self, request): """ - * type: IDENTITY | EQUALITY | WEIGHT + * type: IDENTITY | HUNTINGTONHILL | DHONT * options: [ { option: str, @@ -106,8 +128,11 @@ def post(self, request): if t == 'IDENTITY': return self.identity(opts) + elif t=='HUNTINGTONHILL': return self.HuntingtonHill(options=opts, numEscanyos=numEscanyos) - + + elif t == 'DHONT': + return self.dHont(options=opts, numEscanyos=numEscanyos) return Response({}) diff --git a/decide/voting/models.py b/decide/voting/models.py index b11f983f69..a34112db97 100644 --- a/decide/voting/models.py +++ b/decide/voting/models.py @@ -36,7 +36,7 @@ class Voting(models.Model): start_date = models.DateTimeField(blank=True, null=True) end_date = models.DateTimeField(blank=True, null=True) - tipo_votacion = [("IDENTITY", "IDENTITY"),("HUNTINGTONHILL", "HUNTINGTONHILL")] + tipo_votacion = [("IDENTITY", "IDENTITY"),("HUNTINGTONHILL", "HUNTINGTONHILL"),("DHONT","DHONT")] tipo = models.CharField(choices=tipo_votacion, max_length=20, default="IDENTITY", verbose_name='Count method')