-
Notifications
You must be signed in to change notification settings - Fork 1
/
tableau.py
139 lines (132 loc) · 5.8 KB
/
tableau.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# -*- coding: utf-8 -*-
import tab2html
class constraint :
def __init__(self, index, abbr, describe) :
self.index = index
self.abbr = abbr
self.describe = describe
class data(tab2html.dataMixin) :
def __init__(self, underlying) :
self.underlying = underlying
self.candidates = dict()
self._winners = dict()
self._winner = None
## following is obsolete
# @property
# def winner(self) :
# return self._winner
# @winner.setter
# def winner(self, value) :
# self._winner = value
# self.winners = {value:1}
@property
def winners(self) :
return self._winners
@winners.setter
def winners(self, value) :
self._winners = value
self._winner = tuple(value)[0]
def subtract(vio_dict1, vio_dict2) :
''' get the index of constraints in $vio_dict1 whose degree of violation is bigger
than that in $vio_dict2 '''
ans = dict()
for i1, d1 in vio_dict1.items() :
if i1 not in vio_dict2 :
ans[i1] = d1
elif d1 > vio_dict2[i1] :
ans[i1] = d1 - vio_dict2[i1]
return ans
class InputError(Exception) :
def __init__(self, *args) :
Exception.__init__(self, *args)
class tableau(tab2html.tableauMixin) :
def __init__(self, fname=None, string=None) :
self.constraints = list()
self.datum = list()
#TODO: copier, fromFile, etc.
if fname :
self.readFile(fname)
elif string :
self.readString(string)
def get_constraint(self, index) :
for c in self.constraints :
if c.index == index :
return c
def get_constraint_indices(self) :
return [c.index for c in self.constraints]
def readFile(self, fname) :
''' construct from plain text file (.txt)'''
f = open(fname) ## may fail and raise IOError
self.readLines(f)
def readString(self, s) :
''' construct from plain string '''
self.readLines(s.split('\n'))
def readLines(self, s) :
''' construct from list of text lines '''
mat = [line.strip('\r\n').split('\t') for line in s if line.strip() != '']
self.readMat(mat)
def readMat(self, mat) :
''' construct from table with string elements '''
## extract constraint info
self.constraints = [constraint(index=i, abbr=a, describe=d)
for i, (d, a) in enumerate(zip(mat[0][3:], mat[1][3:]))]
## extract data
self.datum = list()
def addToDatum(onedata) :
''' put information for one input into the structure '''
if onedata != None : ## indeed has extracted data
onedata.winners = onedata.winners ## this is a bit odd, see getter and setter
if len(onedata.winners) == 0 : ## has no winner candidate
raise InputError('no winner form for underlying form "%s"'%(onedata.underlying) )
else :
for winner in onedata.winners :
winner_vio_dict = onedata.candidates[winner]
for can, vio_dict in onedata.candidates.items() :
if ( can not in onedata.winners
and len(subtract(vio_dict, winner_vio_dict)) == 0 ) :
raise InputError('winner candidate "%(win)s is" harmonically bounded by "%(can)s" with underlying form "%(und)s"'
%{'win':winner, 'can':can, 'und':onedata.underlying})
self.datum.append(onedata)
onedata = None ## store the data for current underlying form
for line in mat[2:] : ## data start from 3rd row
## underlying form
underlying = line[0].strip() ## extract underlying form
if underlying != '' : ## the start of a new group of data
addToDatum(onedata)
onedata = data(underlying)
if line[1].strip() == '' : ## empty candidate
raise InputError('empty candidates form when reading underlying form "%s"'%(onedata.underlying))
## extract information of a candidate
onedata.candidates[line[1]] = dict((constraint_index, int(degree))
for constraint_index, degree in enumerate(line[3:]) if degree != '')
## winner candidate
if line[2].strip() != '' : ## if this is a winner
'''
if onedata.winner != None : ## already has a winner
## more than one candidate for single underlying form, which is not allowed for now
raise InputError('more than one winner when reading underlying form %s'%(onedata.underlying))
onedata.winner = line[1]
'''
onedata.winners.update({line[1]:float(line[2])})
addToDatum(onedata) ## don't forget to save the last group of data
def toMat(self) :
mat = list()
ind = self.get_constraint_indices()
## make the head
mat.append(['']*3 + [self.get_constraint(index=i).describe for i in ind])
mat.append(['']*3 + [self.get_constraint(index=i).abbr for i in ind])
## make the body
for d in self.datum :
onemat = [ ['', can, ''] + [str(vio_dict.get(i, '')) for i in ind]
for can, vio_dict in d.candidates.items()]
onemat[0][0] = d.underlying
for i in range(len(onemat)) :
cand = onemat[i][1]
if cand in d.winners :
v = d.winners[cand]
if round(v) == v : v = int(v)
onemat[i][2] = str(v)
mat.extend(onemat)
return mat
def toString(self) :
return '\n'.join('\t'.join(row) for row in self.toMat())