-
Notifications
You must be signed in to change notification settings - Fork 1
/
derivation.py
114 lines (90 loc) · 3.98 KB
/
derivation.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
import json
from copy import deepcopy
class Derivation(object):
def __init__(self, unknown_map, number_map, template,
template_index, word_problem, nouns, numbers):
self.unknown_map = unknown_map
self.number_map = number_map
self.template = template
self.template_index = template_index
self.word_problem = word_problem
self.nouns = nouns
self.numbers = numbers
def copy(self):
return Derivation(deepcopy(self.unknown_map),
deepcopy(self.number_map),
self.template, self.template_index,
self.word_problem, self.nouns,
deepcopy(self.numbers))
def all_unknowns_filled(self):
return not any(v is None for v in self.unknown_map.itervalues())
def all_numbers_filled(self):
return not any(v is None for v in self.number_map.itervalues())
def is_complete(self):
return self.all_unknowns_filled() and self.all_numbers_filled()
def all_ways_to_fill_next_slot(self):
if not self.all_numbers_filled():
return self.all_ways_to_fill_next_number()
if not self.all_unknowns_filled():
return self.all_ways_to_fill_next_unknown()
return None
def all_ways_to_fill_next_number(self):
not_assigned = [s for s in self.number_map
if self.number_map[s] is None]
next_number_slot = sorted(not_assigned, key=str)[0]
derivations = list()
for number in self.numbers:
derivation = self.copy()
derivation.number_map[next_number_slot] = number
derivation.numbers.remove(number)
derivations.append(derivation)
return derivations
def all_ways_to_fill_next_unknown(self):
not_assigned = [s for s in self.unknown_map
if self.unknown_map[s] is None]
next_unknown_slot = sorted(not_assigned, key=str)[0]
derivations = list()
for noun in self.nouns:
derivation = self.copy()
derivation.unknown_map[next_unknown_slot] = noun
derivations.append(derivation)
return derivations
def solve(self):
solutions = list()
for equation in self.template.solution.itervalues():
subs = {k: v['number'] for k, v in self.number_map.iteritems()
if v is not None}
try:
solutions.append(float(equation.full.xreplace(subs)))
except TypeError:
solutions.append(None)
return solutions
def __str__(self):
return json.dumps(self.to_json())
def to_json(self):
return {'unknown_map': {str(k): v for k, v
in self.unknown_map.iteritems()},
'number_map': {str(k): v for k, v
in self.number_map.iteritems()},
'template': self.template.to_json(),
'template_index': self.template_index,
'word_problem': self.word_problem.to_json(),
'nouns': self.nouns,
'numbers': self.numbers}
def initialize_partial_derivations_for_all_templates(wp, templates):
numbers = wp.nlp.numbers()
nouns = wp.nlp.nouns()
partial_derivations = list()
for template_index, template in enumerate(templates):
slots = set()
for eq in template.equations:
slots.update(eq.symbols)
unknown_slots = [s for s in slots if 'u_' in str(s)]
number_slots = [s for s in slots if 'n_' in str(s)]
unknown_map = {u: None for u in unknown_slots}
number_map = {n: None for n in number_slots}
partial_derivations.append(Derivation(unknown_map, number_map,
template, template_index,
wp, nouns,
deepcopy(numbers)))
return partial_derivations