aac-metrics 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|