aac-metrics 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/aac-metrics/loader.rb +49 -28
- data/lib/aac-metrics/metrics.rb +139 -42
- data/sets/base_words.en.json +894 -0
- data/sets/pc36-6616542987.obfset +207 -0
- data/sets/qc112-a67653dd81.en.obfset +4892 -2015
- data/sets/qc24-bcbee2ea83.en.obfset +1331 -481
- data/sets/qc40-5ceeb28275.obfset +11385 -0
- data/sets/qc60-61bbf6171e.common.en.obfset +2714 -1224
- data/sets/qc84-d83fa84056.obfset +24996 -0
- data/sets/sfy-c45a81c416.common.en.obfset +863 -776
- data/sets/vf112-253f46504a.obfset +28601 -0
- data/sets/vf24-9d3442b880.obfset +13055 -0
- data/sets/vf40-0355b86ede.obfset +16088 -0
- data/sets/vf60-a37d6d6577.obfset +20557 -0
- data/sets/vf84-02166358c0.obfset +25571 -0
- data/sets/wp20-163743e671.obfset +39129 -0
- data/sets/wp42-f67dc6f4a9.obfset +84948 -0
- data/sets/wp60-ce5120b0d2.obfset +106281 -0
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 554fc52ede0b5dffdcf9315ec279a9f42a3ef2a44a324195018eda56538336b1
|
4
|
+
data.tar.gz: 2b082df38edf52ddf495045969db894ef02f7718641658d8d1ca4b012456e14c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58c3c7e8128b0bee8754baa3b218a36491cf985ed752b917733a0508bc9a4c8abe8c3e2c40ddcb7cd9098bea51a6c3d9143f5ba4cbd2d9098f59f16899bf1e0b
|
7
|
+
data.tar.gz: c9e2ec540feee357aaf6b1a20b11e5b938d2f4f8d28ba6d03eee80245167b1eb339ab5a2e1440588db6a31cffbe27bee37a44d6ef35f0078f5381d363c06226c
|
data/lib/aac-metrics/loader.rb
CHANGED
@@ -37,6 +37,29 @@ module AACMetrics::Loader
|
|
37
37
|
end
|
38
38
|
if obfset
|
39
39
|
json = JSON.parse(File.read(obfset))
|
40
|
+
relations_hash = {}
|
41
|
+
json.each do |board|
|
42
|
+
board['grid']['order'].each_with_index do |row, row_idx|
|
43
|
+
row.each_with_index do |id, col_idx|
|
44
|
+
button = id && board['buttons'].detect{|b| b['id'] == id }
|
45
|
+
if button && button['label'] && !button['clone_id']
|
46
|
+
ref = "#{board['grid']['rows']}x#{board['grid']['columns']}-#{row_idx}.#{col_idx}"
|
47
|
+
pre = 'c'
|
48
|
+
relations_hash["cpre#{ref}-#{button['label']}"] ||= []
|
49
|
+
relations_hash["cpre#{ref}-#{button['label']}"] << [board, button]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
relations_hash.each do |id, cells|
|
55
|
+
if cells.length > 1
|
56
|
+
cells.each do |board, button|
|
57
|
+
board['clone_ids'] ||= []
|
58
|
+
board['clone_ids'] << id
|
59
|
+
button['clone_id'] ||= id
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
40
63
|
elsif analysis
|
41
64
|
json = JSON.parse(File.read(analysis))
|
42
65
|
end
|
@@ -84,6 +107,7 @@ module AACMetrics::Loader
|
|
84
107
|
path = paths.shift
|
85
108
|
visited_paths[path] = idx
|
86
109
|
new_json = {
|
110
|
+
"format" => 'obs',
|
87
111
|
"id" => "brd#{idx}",
|
88
112
|
"buttons" => [],
|
89
113
|
"grid" => {},
|
@@ -158,28 +182,29 @@ module AACMetrics::Loader
|
|
158
182
|
# treat action buttons for metrics
|
159
183
|
new_btn = nil
|
160
184
|
end
|
161
|
-
# temporarily save semantic_id and
|
185
|
+
# temporarily save semantic_id and possibly clone_id for later use
|
162
186
|
# 1. Buttons in the same location with the same
|
163
187
|
# semantic_id should be marked in the obfset as having
|
164
188
|
# the same semantic_id
|
165
189
|
# 2. Buttons in the same location with the same label & voc
|
166
190
|
# and same load_board setting
|
167
191
|
# should be marked in the obfset as having the same clone_id
|
168
|
-
ref = "#{new_json['grid']['rows']}x#{new_json['grid']['columns']}-#{
|
192
|
+
ref = "#{new_json['grid']['rows']}x#{new_json['grid']['columns']}-#{row_idx}.#{col_idx}"
|
169
193
|
if btn['semantic_id']
|
170
194
|
relations_hash["s#{ref}-#{btn['semantic_id']}"] ||= []
|
171
195
|
relations_hash["s#{ref}-#{btn['semantic_id']}"] << [new_json['id'], new_btn['id']]
|
172
196
|
end
|
173
|
-
if new_btn['label']
|
174
|
-
#
|
175
|
-
pre =
|
197
|
+
if new_btn && new_btn['label']
|
198
|
+
#pre = new_btn['load_board'] ? 'cl' : 'c'
|
199
|
+
pre = 'c'
|
176
200
|
relations_hash["#{pre}#{ref}-#{new_btn['label']}"] ||= []
|
177
|
-
relations_hash["#{pre}#{ref}-#{new_btn['label']}"]
|
201
|
+
relations_hash["#{pre}#{ref}-#{new_btn['label']}"] << [new_json['id'], new_btn['id']]
|
178
202
|
end
|
179
|
-
if do_ingest && new_btn['label']
|
203
|
+
if do_ingest && new_btn && new_btn['label']
|
180
204
|
str = new_btn['label'].downcase.sub(/^\s+/, '').sub(/\s+$/, '')
|
181
205
|
if str.scan(/\s+/).length < 2
|
182
206
|
word_hash = Digest::MD5.hexdigest(str)[0, 10]
|
207
|
+
# Will need to re-evaluate hash process if it ever finds a collision with an already-saved word
|
183
208
|
raise "collision!" if words[word_hash] && words[word_hash] != str
|
184
209
|
if add_words || words[word_hash]
|
185
210
|
words[word_hash] = str
|
@@ -197,9 +222,18 @@ module AACMetrics::Loader
|
|
197
222
|
boards << new_json
|
198
223
|
end
|
199
224
|
end
|
225
|
+
# finalize all board paths once done iterating
|
226
|
+
boards.each do |brd|
|
227
|
+
brd['buttons'].each do |btn|
|
228
|
+
if btn['load_board'] && btn['load_board']['tmp_path']
|
229
|
+
btn['load_board']['id'] = "brd#{visited_paths[btn['load_board']['tmp_path']]}" if visited_paths[btn['load_board']['tmp_path']]
|
230
|
+
btn['load_board'].delete('tmp_path')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
200
234
|
# any semantic_id or clone_id repeats must be recorded
|
201
235
|
relations_hash.each do |id, btns|
|
202
|
-
if btns && btns.length >
|
236
|
+
if btns && btns.length > 1
|
203
237
|
btns.each do |brd_id, btn_id|
|
204
238
|
brd = boards.detect{|b| b['id'] == brd_id }
|
205
239
|
if brd && brd['buttons']
|
@@ -220,32 +254,18 @@ module AACMetrics::Loader
|
|
220
254
|
#
|
221
255
|
end
|
222
256
|
end
|
223
|
-
boards.each do |brd|
|
224
|
-
brd['buttons'].each do |btn|
|
225
|
-
if btn['load_board'] && btn['load_board']['tmp_path']
|
226
|
-
btn['load_board']['id'] = "brd#{visited_paths[btn['load_board']['tmp_path']]}" if visited_paths[btn['load_board']['tmp_path']]
|
227
|
-
btn['load_board'].delete('tmp_path')
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
257
|
# TODO: record whether the board set is expected to have auto-home
|
232
258
|
{boards: boards, words: words, words_path: words_path}
|
233
259
|
end
|
234
260
|
|
235
|
-
# TODO: Qualitative assessments of common vocabularies,
|
236
|
-
# gather perspectives on what makes a "good" vocabulary
|
237
|
-
# and collect reviews from field experts, also free
|
238
|
-
# response sections.
|
239
|
-
# Some criteria:
|
240
|
-
# - works well for age group X, Y, Z
|
241
|
-
# - works well for a beginning communicator
|
242
|
-
# - allows long-term growth as-is
|
243
|
-
# - comprehensive core
|
244
|
-
# -
|
245
|
-
|
246
261
|
def self.ingest(fn, token=nil)
|
247
262
|
output = nil
|
248
263
|
boards = nil
|
264
|
+
if fn.match(/manifest.json/)
|
265
|
+
json = JSON.parse(File.read(fn))
|
266
|
+
root_fn = json['root']
|
267
|
+
fn = fn.sub(/manifest.json/, root_fn)
|
268
|
+
end
|
249
269
|
if fn.match(/\.obfset$/)
|
250
270
|
boards = retrieve(fn, false)
|
251
271
|
output = fn
|
@@ -268,7 +288,8 @@ module AACMetrics::Loader
|
|
268
288
|
end
|
269
289
|
end
|
270
290
|
if boards
|
271
|
-
analysis = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'sets',
|
291
|
+
analysis = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'sets', output.sub(/\.obfset$/, '.analysis')))
|
292
|
+
analysis = output.sub(/\.obfset$/, '.analysis')
|
272
293
|
res = AACMetrics::Metrics.analyze(boards, false)
|
273
294
|
f = File.open(analysis, 'w')
|
274
295
|
f.write(JSON.pretty_generate(res))
|
data/lib/aac-metrics/metrics.rb
CHANGED
@@ -5,34 +5,38 @@
|
|
5
5
|
# - the vocabulary organization of this set makes sense
|
6
6
|
# - this set provides clear opportunities for user-specific words to be added
|
7
7
|
# - grammatical forms, growth over time
|
8
|
+
# - works well for age group X, Y, Z
|
9
|
+
# - works well for a beginning communicator
|
10
|
+
# - allows long-term growth as-is
|
11
|
+
# - comprehensive core
|
12
|
+
|
8
13
|
# Effort algorithms for scanning/eyes
|
9
|
-
# TODO: manual way to flag button as conceptually
|
10
|
-
# related to the same-locaed button on the
|
11
|
-
# prior board, allowing for a discounted penalty
|
12
14
|
module AACMetrics::Metrics
|
13
|
-
#
|
14
|
-
# 1. When navigating from one board to the next, grid locations
|
15
|
+
# A. When navigating from one board to the next, grid locations
|
15
16
|
# with the same clone_id or semantic_id should result in a
|
16
17
|
# discount to overall search based more on the number of
|
17
18
|
# uncloned/unsemantic buttons than the number of total buttons
|
18
19
|
# (perhaps also factoring in the percent of board with that
|
19
20
|
# id present in the full board set)
|
20
|
-
#
|
21
|
+
# B. When selecting a button with a semantic_id or clone_id,
|
21
22
|
# a discount to both search and selection should
|
22
23
|
# be applied based on the percent of boards that
|
23
24
|
# contain the same id at that grid location
|
24
|
-
#
|
25
|
+
# C. When selecting a button with a semantic_id or clone_id,
|
25
26
|
# if the same id was present on the previous board,
|
26
27
|
# an additional discount to search and selection should be applied
|
27
|
-
|
28
|
+
# D When selecting a button with a semantic_id or clone_id,
|
29
|
+
# apply a steep discount to the button in the same location
|
30
|
+
# as the link used to get there if they share an id
|
31
|
+
def self.analyze(obfset, output=true, include_obfset=false)
|
28
32
|
locale = nil
|
29
33
|
buttons = []
|
30
|
-
|
34
|
+
set_refs = {}
|
31
35
|
grid = {}
|
32
36
|
|
33
37
|
if obfset.is_a?(Hash) && obfset['buttons']
|
34
38
|
locale = obfset['locale'] || 'en'
|
35
|
-
|
39
|
+
set_refs = obfset['reference_counts']
|
36
40
|
grid = obfset['grid']
|
37
41
|
buttons = []
|
38
42
|
obfset['buttons'].each do |btn|
|
@@ -49,13 +53,14 @@ module AACMetrics::Metrics
|
|
49
53
|
else
|
50
54
|
visited_board_ids = {}
|
51
55
|
to_visit = [{board: obfset[0], level: 0, entry_x: 1.0, entry_y: 1.0}]
|
52
|
-
|
56
|
+
set_refs = {}
|
53
57
|
rows_tally = 0.0
|
54
58
|
cols_tally = 0.0
|
55
59
|
root_rows = nil
|
56
60
|
root_cols = nil
|
57
61
|
# Gather repeated words/concepts
|
58
62
|
obfset.each do |board|
|
63
|
+
# try to figure out the average grid size for board set
|
59
64
|
root_rows ||= board['grid']['rows']
|
60
65
|
root_cols ||= board['grid']['columns']
|
61
66
|
rows_tally += board['grid']['rows']
|
@@ -63,25 +68,27 @@ module AACMetrics::Metrics
|
|
63
68
|
# determine frequency within the board set
|
64
69
|
# for each semantic_id and clone_id
|
65
70
|
if board['clone_ids']
|
66
|
-
|
67
|
-
|
68
|
-
|
71
|
+
board['clone_ids'].each do |id|
|
72
|
+
set_refs[id] ||= 0
|
73
|
+
set_refs[id] += 1
|
69
74
|
end
|
70
75
|
end
|
71
76
|
if board['semantic_ids']
|
72
|
-
|
73
|
-
|
74
|
-
|
77
|
+
board['semantic_ids'].each do |id|
|
78
|
+
set_refs[id] ||= 0
|
79
|
+
set_refs[id] += 1
|
75
80
|
end
|
76
81
|
end
|
77
82
|
end
|
83
|
+
# If the average grid size is much different than the root
|
84
|
+
# grid size, only then use the average as the size for this board set
|
78
85
|
if (rows_tally / obfset.length.to_f - root_rows).abs > 3 || (cols_tally / obfset.length.to_f - root_cols).abs > 3
|
79
86
|
root_rows = (rows_tally / obfset.length.to_f).floor
|
80
87
|
root_cols = (cols_tally / obfset.length.to_f).floor
|
81
88
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
89
|
+
set_pcts = {}
|
90
|
+
set_refs.each do |id, cnt|
|
91
|
+
set_pcts[id] = cnt.to_f / obfset.length.to_f
|
85
92
|
end
|
86
93
|
locale = obfset[0]['locale']
|
87
94
|
known_buttons = {}
|
@@ -102,20 +109,56 @@ module AACMetrics::Metrics
|
|
102
109
|
# whose semantic_id or clone_id is repeated in the board set
|
103
110
|
# -0.0025 (* pct of matching boards) for semantic_id
|
104
111
|
# -0.005 (* pct of matching boards) for clone_id
|
112
|
+
reuse_discount = 0.0
|
105
113
|
board[:board]['grid']['rows'].times do |row_idx|
|
106
114
|
board[:board]['grid']['columns'].times do |col_idx|
|
107
115
|
button_id = (board[:board]['grid']['order'][row_idx] || [])[col_idx]
|
108
116
|
button = board[:board]['buttons'].detect{|b| b['id'] == button_id }
|
109
|
-
if button && button['clone_id'] &&
|
110
|
-
|
111
|
-
elsif button && button['semantic_id'] &&
|
112
|
-
|
117
|
+
if button && button['clone_id'] && set_pcts[button['clone_id']]
|
118
|
+
reuse_discount += REUSED_CLONE_FROM_OTHER_DISCOUNT * set_pcts[button['clone_id']]
|
119
|
+
elsif button && button['semantic_id'] && set_pcts[button['semantic_id']]
|
120
|
+
reuse_discount += REUSED_SEMANTIC_FROM_OTHER_DISCOUNT * set_pcts[button['semantic_id']]
|
113
121
|
end
|
114
122
|
end
|
115
123
|
end
|
116
|
-
|
124
|
+
board_effort -= reuse_discount
|
117
125
|
prior_buttons = 0
|
118
126
|
|
127
|
+
# Calculate the percent of links to this board
|
128
|
+
# that had or were linked by clone_ids or semantic_ids
|
129
|
+
board_pcts = {}
|
130
|
+
obfset.each do |brd|
|
131
|
+
brd['buttons'].each do |link_btn|
|
132
|
+
# For every board that links to this board
|
133
|
+
if link_btn['load_board'] && link_btn['load_board']['id'] == board[:board]['id']
|
134
|
+
board_pcts['all'] ||= 0
|
135
|
+
board_pcts['all'] += 1
|
136
|
+
# Count how many of those links have a clone_id or semantic_id
|
137
|
+
if link_btn['clone_id']
|
138
|
+
board_pcts[link_btn['clone_id']] ||= 0
|
139
|
+
board_pcts[link_btn['clone_id']] += 1
|
140
|
+
end
|
141
|
+
if link_btn['semantic_id']
|
142
|
+
board_pcts[link_btn['semantic_id']] ||= 0
|
143
|
+
board_pcts[link_btn['semantic_id']] += 1
|
144
|
+
end
|
145
|
+
# Also count all the clone_ids and semantic_ids
|
146
|
+
# anywhere on the boards that link to this one
|
147
|
+
(brd['clone_ids'] || []).uniq.each do |cid|
|
148
|
+
board_pcts["upstream-#{cid}"] ||= 0
|
149
|
+
board_pcts["upstream-#{cid}"] += 1
|
150
|
+
end
|
151
|
+
(brd['semantic_ids'] || []).uniq.each do |sid|
|
152
|
+
board_pcts["upstream-#{sid}"] ||= 0
|
153
|
+
board_pcts["upstream-#{sid}"] += 1
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
board_pcts.each do |id, cnt|
|
159
|
+
board_pcts[id] = board_pcts[id].to_f / board_pcts['all'].to_f
|
160
|
+
end
|
161
|
+
|
119
162
|
board[:board]['grid']['rows'].times do |row_idx|
|
120
163
|
board[:board]['grid']['columns'].times do |col_idx|
|
121
164
|
button_id = (board[:board]['grid']['order'][row_idx] || [])[col_idx]
|
@@ -125,13 +168,34 @@ module AACMetrics::Metrics
|
|
125
168
|
x = (btn_width / 2) + (btn_width * col_idx)
|
126
169
|
y = (btn_height / 2) + (btn_height * row_idx)
|
127
170
|
# prior_buttons = (row_idx * board[:board]['grid']['columns']) + col_idx
|
171
|
+
# calculate the percentage of links that point to this button
|
172
|
+
# and match on semantic_id or clone_id
|
128
173
|
effort = 0
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
|
174
|
+
# Additional discount on board search effort,
|
175
|
+
# remember that semantic_id and clone_id are
|
176
|
+
# keyed to the same grid location, so matches only
|
177
|
+
# apply to that specific location
|
178
|
+
# - if this button's semantic_id or clone_id
|
179
|
+
# was also present anywhere on the prior board
|
180
|
+
# board_effort * 0.5 for semantic_id
|
181
|
+
# board_effort * 0.33 for clone_id
|
182
|
+
# - if this button's semantic_id or clone_id
|
183
|
+
# is directly used to navigate to this board
|
184
|
+
# board_effort * 0.1 for semantic_id
|
185
|
+
# board_effort * 0.1 for clone_id
|
186
|
+
button_effort = board_effort
|
187
|
+
if board_pcts[button['semantic_id']]
|
188
|
+
# TODO: Pull out these magic numbers
|
189
|
+
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['semantic_id']]].min
|
190
|
+
elsif board_pcts["upstream-#{button['semantic_id']}"]
|
191
|
+
button_effort = [button_effort, button_effort * RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['semantic_id']}"]].min
|
192
|
+
end
|
193
|
+
if board_pcts[button['clone_id']]
|
194
|
+
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['clone_id']]].min
|
195
|
+
elsif board_pcts["upstream-#{button['clone_id']}"]
|
196
|
+
button_effort = [button_effort, button_effort * RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['clone_id']}"]].min
|
197
|
+
end
|
198
|
+
effort += button_effort
|
135
199
|
# add effort for percent distance from entry point
|
136
200
|
distance = distance_effort(x, y, board[:entry_x], board[:entry_y])
|
137
201
|
# TODO: decrease effective distance if the semantic_id or clone_id:
|
@@ -141,6 +205,24 @@ module AACMetrics::Metrics
|
|
141
205
|
# - was also present on the prior board (total)
|
142
206
|
# distance * 0.5 for semantic_id
|
143
207
|
# distance * 0.33 for clone_id
|
208
|
+
# - is directly used to navigate to this board
|
209
|
+
# distance * 0.1 * (pct of links that match) for semantic_id
|
210
|
+
# distance * 0.1 * (pct of links that match) for clone_id
|
211
|
+
if board_pcts[button['semantic_id']]
|
212
|
+
distance = [distance, distance * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['semantic_id']]].min
|
213
|
+
elsif board_pcts["upstream-#{button['semantic_id']}"]
|
214
|
+
distance = [distance, distance * RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['semantic_id']}"]].min
|
215
|
+
elsif set_pcts[button['semantic_id']]
|
216
|
+
distance = [distance, distance * RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT / set_pcts[button['semantic_id']]].min
|
217
|
+
end
|
218
|
+
if board_pcts[button['clone_id']]
|
219
|
+
distance = [distance, distance * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['clone_id']]].min
|
220
|
+
elsif board_pcts["upstream-#{button['clone_id']}"]
|
221
|
+
distance = [distance, distance * RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['clone_id']}"]].min
|
222
|
+
elsif set_pcts[button['clone_id']]
|
223
|
+
distance = [distance, distance * RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT / set_pcts[button['clone_id']]].min
|
224
|
+
end
|
225
|
+
|
144
226
|
effort += distance
|
145
227
|
if distance > DISTANCE_THRESHOLD_TO_SKIP_VISUAL_SCAN || (board[:entry_x] == 1.0 && board[:entry_y] == 1.0)
|
146
228
|
# add small effort for every prior (visible) button when visually scanning
|
@@ -170,31 +252,39 @@ module AACMetrics::Metrics
|
|
170
252
|
end
|
171
253
|
if try_visit
|
172
254
|
next_board = obfset.detect{|brd| brd['id'] == button['load_board']['id'] }
|
173
|
-
|
255
|
+
change_effort = BOARD_CHANGE_PROCESSING_EFFORT
|
174
256
|
if next_board
|
175
257
|
to_visit.push({
|
176
258
|
board: next_board,
|
177
259
|
level: board[:level] + 1,
|
178
|
-
prior_effort: effort +
|
260
|
+
prior_effort: effort + change_effort,
|
179
261
|
entry_x: x,
|
180
|
-
entry_y: y
|
262
|
+
entry_y: y,
|
263
|
+
entry_clone_id: button['clone_id'],
|
264
|
+
entry_semantic_id: button['semantic_id']
|
181
265
|
})
|
182
266
|
end
|
183
267
|
end
|
184
268
|
else
|
185
269
|
word = button['label']
|
186
270
|
existing = known_buttons[word]
|
187
|
-
|
188
|
-
|
189
|
-
|
271
|
+
if !existing || effort < existing[:effort] #board[:level] < existing[:level]
|
272
|
+
if board_pcts[button['clone_id']]
|
273
|
+
effort -= [BOARD_CHANGE_PROCESSING_EFFORT, BOARD_CHANGE_PROCESSING_EFFORT * 0.3 / board_pcts[button['clone_id']]].min
|
274
|
+
elsif board_pcts[button['semantic_id']]
|
275
|
+
effort -= [BOARD_CHANGE_PROCESSING_EFFORT, BOARD_CHANGE_PROCESSING_EFFORT * 0.5 / board_pcts[button['semantic_id']]].min
|
276
|
+
end
|
277
|
+
|
190
278
|
known_buttons[word] = {
|
191
279
|
id: "#{button['id']}::#{board[:board]['id']}",
|
192
280
|
label: word,
|
193
281
|
level: board[:level],
|
194
|
-
effort: effort
|
282
|
+
effort: effort,
|
195
283
|
}
|
196
284
|
end
|
197
285
|
end
|
286
|
+
button['effort'] = effort
|
287
|
+
|
198
288
|
end
|
199
289
|
end
|
200
290
|
end
|
@@ -212,7 +302,7 @@ module AACMetrics::Metrics
|
|
212
302
|
locale: locale,
|
213
303
|
total_boards: total_boards,
|
214
304
|
total_buttons: buttons.length,
|
215
|
-
reference_counts:
|
305
|
+
reference_counts: set_refs,
|
216
306
|
grid: {
|
217
307
|
rows: root_rows,
|
218
308
|
columns: root_cols
|
@@ -228,12 +318,19 @@ module AACMetrics::Metrics
|
|
228
318
|
|
229
319
|
SQRT2 = Math.sqrt(2)
|
230
320
|
BUTTON_SIZE_MULTIPLIER = 0.09
|
231
|
-
FIELD_SIZE_MULTIPLIER = 0.
|
232
|
-
VISUAL_SCAN_MULTIPLIER = 0.
|
321
|
+
FIELD_SIZE_MULTIPLIER = 0.005
|
322
|
+
VISUAL_SCAN_MULTIPLIER = 0.015
|
233
323
|
BOARD_CHANGE_PROCESSING_EFFORT = 1.0
|
234
|
-
DISTANCE_MULTIPLIER = 0.
|
324
|
+
DISTANCE_MULTIPLIER = 0.4
|
235
325
|
DISTANCE_THRESHOLD_TO_SKIP_VISUAL_SCAN = 0.1
|
236
326
|
SKIPPED_VISUAL_SCAN_DISTANCE_MULTIPLIER = 0.5
|
327
|
+
SAME_LOCATION_AS_PRIOR_DISCOUNT = 0.1
|
328
|
+
RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT = 0.5
|
329
|
+
RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT = 0.6
|
330
|
+
RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT = 0.33
|
331
|
+
RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT = 0.4
|
332
|
+
REUSED_SEMANTIC_FROM_OTHER_DISCOUNT = 0.0025
|
333
|
+
REUSED_CLONE_FROM_OTHER_DISCOUNT = 0.005
|
237
334
|
|
238
335
|
def self.button_size_effort(rows, cols)
|
239
336
|
BUTTON_SIZE_MULTIPLIER * (rows + cols) / 2
|