aac-metrics 0.1.8 → 0.2.1
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 +13 -2
- data/lib/aac-metrics/metrics.rb +86 -27
- data/sets/common_words.en.json +1426 -1424
- data/sets/fringe.en.json +12 -129
- data/sets/l84f-e9fafa55d4.common.en.analysis +27620 -27480
- data/sets/l84f-e9fafa55d4.common.en.obfset +14784 -4752
- data/sets/l84ns-2f9h2f9.en.obfset +82466 -0
- data/sets/wp108-c428d7f2dc.en.analysis +16243 -15551
- data/sets/wp108-c428d7f2dc.en.obfset +7906 -2634
- data/sets/wp20-163743e671.obfset +266 -78
- data/sets/wp42-f67dc6f4a9.obfset +3767 -1549
- data/sets/wp60-ce5120b0d2.obfset +5694 -2385
- data/sets/wp80-dad3aeda5e.common.en.analysis +15423 -14787
- data/sets/wp80-dad3aeda5e.common.en.obfset +8049 -2846
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bddb8e430a21868a5b26312fb5924f36b914446dc212d849330462768fd9b233
|
4
|
+
data.tar.gz: c5ddd0e2b835678f0dabf8743099b29d462612d94a4aa4dd261e1cb7337eaa02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 876e09d6be2b2e2b7579c11bb06367296ee7fbba627db0f8d421b4e60d2b7042d9a41433f9b1af10c78a6fc8ac84077170224e059a5a5ba30db6b217cab56936
|
7
|
+
data.tar.gz: 5072598db0226690da77985e4e1ed760b24f0d0edc2bc99a5961e59d7f8e8bfa549073f4d0b223559ba48d7d2348556041d8b513944e5427c9c158db3b467f6c
|
data/lib/aac-metrics/loader.rb
CHANGED
@@ -20,6 +20,7 @@ module AACMetrics::Loader
|
|
20
20
|
}
|
21
21
|
if button['load_board'] && button['load_board']['id']
|
22
22
|
new_button['load_board'] = {'id' => button['load_board']['id']}
|
23
|
+
new_button['load_board']['add_to_sentence'] = true if button['load_board']['add_to_sentence']
|
23
24
|
end
|
24
25
|
new_board['buttons'].push(new_button)
|
25
26
|
end
|
@@ -177,6 +178,7 @@ module AACMetrics::Loader
|
|
177
178
|
else
|
178
179
|
puts "Link found with no access #{btn['load_board'].to_json}"
|
179
180
|
end
|
181
|
+
new_btn['load_board']['add_to_sentence'] = true if new_btn['load_board'] && btn['load_board']['add_to_sentence']
|
180
182
|
elsif btn['action']
|
181
183
|
# TODO: track keyboard actions and don't
|
182
184
|
# treat action buttons for metrics
|
@@ -391,9 +393,18 @@ module AACMetrics::Loader
|
|
391
393
|
end
|
392
394
|
end
|
393
395
|
all_words.uniq!
|
394
|
-
@@
|
396
|
+
@@fringe_words[locale] = all_words
|
395
397
|
end
|
396
|
-
|
398
|
+
|
399
|
+
def self.common_fringe_words(locale)
|
400
|
+
@@common_fringe_words ||= {}
|
401
|
+
return @@common_fringe_words[locale] if @@common_fringe_words[locale]
|
402
|
+
common = self.common_words(locale)['words']
|
403
|
+
core = self.core_lists('en').map{|r| r['words'] }.flatten.compact.uniq
|
404
|
+
all_words = common - core
|
405
|
+
@@common_fringe_words[locale] = all_words
|
406
|
+
end
|
407
|
+
|
397
408
|
def self.base_words(locale)
|
398
409
|
@@base_words ||= {}
|
399
410
|
return @@base_words[locale] if @@base_words[locale]
|
data/lib/aac-metrics/metrics.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# TODO:
|
2
2
|
# Qualitative evaluation criteria:
|
3
|
-
# - this set
|
4
|
-
# - this set
|
5
|
-
# -
|
6
|
-
# - this set provides clear
|
7
|
-
# - grammatical forms
|
8
|
-
# -
|
9
|
-
# -
|
10
|
-
# -
|
11
|
-
# -
|
3
|
+
# - this set looks easy to learn for communicators
|
4
|
+
# - this set looks easy to learn for supporters
|
5
|
+
# - this vocabulary organization of this set makes sense
|
6
|
+
# - this set provides clear locations for user-specific words to be added
|
7
|
+
# - this set supports the use of grammatical forms (tenses and other inflections)
|
8
|
+
# - this set provides predefined simplification for beginning communicators
|
9
|
+
# - this set allows for long-term vocabulary growth over time
|
10
|
+
# - this vocabulary looks like it will work well for young users
|
11
|
+
# - this vocabulary looks like it will work well for adult users
|
12
12
|
|
13
13
|
# Effort algorithms for scanning/eyes
|
14
14
|
module AACMetrics::Metrics
|
@@ -54,6 +54,7 @@ module AACMetrics::Metrics
|
|
54
54
|
visited_board_ids = {}
|
55
55
|
to_visit = [{board: obfset[0], level: 0, entry_x: 1.0, entry_y: 1.0}]
|
56
56
|
set_refs = {}
|
57
|
+
cell_refs = {}
|
57
58
|
rows_tally = 0.0
|
58
59
|
cols_tally = 0.0
|
59
60
|
root_rows = nil
|
@@ -73,6 +74,13 @@ module AACMetrics::Metrics
|
|
73
74
|
set_refs[id] += 1
|
74
75
|
end
|
75
76
|
end
|
77
|
+
board['grid']['rows'].times do |row_idx|
|
78
|
+
board['grid']['columns'].times do |col_idx|
|
79
|
+
id = (board['grid']['order'][row_idx] || [])[col_idx]
|
80
|
+
cell_refs["#{row_idx}.#{col_idx}"] ||= 0.0
|
81
|
+
cell_refs["#{row_idx}.#{col_idx}"] += id ? 1.0 : 0.25
|
82
|
+
end
|
83
|
+
end
|
76
84
|
if board['semantic_ids']
|
77
85
|
board['semantic_ids'].each do |id|
|
78
86
|
set_refs[id] ||= 0
|
@@ -88,7 +96,8 @@ module AACMetrics::Metrics
|
|
88
96
|
end
|
89
97
|
set_pcts = {}
|
90
98
|
set_refs.each do |id, cnt|
|
91
|
-
|
99
|
+
loc = id.split(/-/)[1]
|
100
|
+
set_pcts[id] = cnt.to_f / (cell_refs[loc] || obfset.length).to_f
|
92
101
|
end
|
93
102
|
locale = obfset[0]['locale']
|
94
103
|
known_buttons = {}
|
@@ -115,9 +124,9 @@ module AACMetrics::Metrics
|
|
115
124
|
button_id = (board[:board]['grid']['order'][row_idx] || [])[col_idx]
|
116
125
|
button = board[:board]['buttons'].detect{|b| b['id'] == button_id }
|
117
126
|
if button && button['clone_id'] && set_pcts[button['clone_id']]
|
118
|
-
reuse_discount +=
|
127
|
+
reuse_discount += REUSED_CLONE_FROM_OTHER_BONUS * set_pcts[button['clone_id']]
|
119
128
|
elsif button && button['semantic_id'] && set_pcts[button['semantic_id']]
|
120
|
-
reuse_discount +=
|
129
|
+
reuse_discount += REUSED_SEMANTIC_FROM_OTHER_BONUS * set_pcts[button['semantic_id']]
|
121
130
|
end
|
122
131
|
end
|
123
132
|
end
|
@@ -186,9 +195,13 @@ module AACMetrics::Metrics
|
|
186
195
|
button_effort = board_effort
|
187
196
|
if board_pcts[button['semantic_id']]
|
188
197
|
# TODO: Pull out these magic numbers
|
198
|
+
prior = button_effort
|
189
199
|
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['semantic_id']]].min
|
200
|
+
# puts " #{button['label']} #{prior.round(1)} - #{prior - button_effort}"
|
190
201
|
elsif board_pcts["upstream-#{button['semantic_id']}"]
|
202
|
+
prior = button_effort
|
191
203
|
button_effort = [button_effort, button_effort * RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['semantic_id']}"]].min
|
204
|
+
# puts " #{button['label']} #{prior.round(1)} - #{prior - button_effort}"
|
192
205
|
end
|
193
206
|
if board_pcts[button['clone_id']]
|
194
207
|
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['clone_id']]].min
|
@@ -237,6 +250,10 @@ module AACMetrics::Metrics
|
|
237
250
|
effort += board[:prior_effort] || 0
|
238
251
|
prior_buttons += 1
|
239
252
|
|
253
|
+
# TODO: If any board links are sticky, or if
|
254
|
+
# the board set isn't auto-home, or any board links
|
255
|
+
# are add_to_sentence, then the logic will be different
|
256
|
+
# for calculating effort scores, since the route matters
|
240
257
|
if button['load_board']
|
241
258
|
try_visit = false
|
242
259
|
# For linked buttons, only traverse if
|
@@ -265,7 +282,8 @@ module AACMetrics::Metrics
|
|
265
282
|
})
|
266
283
|
end
|
267
284
|
end
|
268
|
-
|
285
|
+
end
|
286
|
+
if !button['load_board'] || button['load_board']['add_to_sentence']
|
269
287
|
word = button['label']
|
270
288
|
existing = known_buttons[word]
|
271
289
|
if !existing || effort < existing[:effort] #board[:level] < existing[:level]
|
@@ -326,11 +344,11 @@ module AACMetrics::Metrics
|
|
326
344
|
SKIPPED_VISUAL_SCAN_DISTANCE_MULTIPLIER = 0.5
|
327
345
|
SAME_LOCATION_AS_PRIOR_DISCOUNT = 0.1
|
328
346
|
RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT = 0.5
|
329
|
-
RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT = 0.
|
347
|
+
RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT = 0.5
|
348
|
+
REUSED_SEMANTIC_FROM_OTHER_BONUS = 0.0025
|
330
349
|
RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT = 0.33
|
331
|
-
RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT = 0.
|
332
|
-
|
333
|
-
REUSED_CLONE_FROM_OTHER_DISCOUNT = 0.005
|
350
|
+
RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT = 0.33
|
351
|
+
REUSED_CLONE_FROM_OTHER_BONUS = 0.005
|
334
352
|
|
335
353
|
def self.button_size_effort(rows, cols)
|
336
354
|
BUTTON_SIZE_MULTIPLIER * (rows + cols) / 2
|
@@ -407,6 +425,7 @@ module AACMetrics::Metrics
|
|
407
425
|
synonyms = AACMetrics::Loader.synonyms(target[:locale])
|
408
426
|
sentences = AACMetrics::Loader.sentences(target[:locale])
|
409
427
|
fringe = AACMetrics::Loader.fringe_words(target[:locale])
|
428
|
+
common_fringe = AACMetrics::Loader.common_fringe_words(target[:locale])
|
410
429
|
common_words_obj['efforts'].each{|w, e| sortable_efforts[w] ||= e }
|
411
430
|
common_words = common_words_obj['words']
|
412
431
|
|
@@ -476,6 +495,7 @@ module AACMetrics::Metrics
|
|
476
495
|
res[:cores] = {
|
477
496
|
:common => {name: "Common Word List", list: common_words, average_effort: common_effort, comp_effort: comp_effort}
|
478
497
|
}
|
498
|
+
res[:care_components] = {}
|
479
499
|
target_effort_tally = 0.0
|
480
500
|
comp_effort_tally = 0.0
|
481
501
|
# For each core list, find any missing words, and compute
|
@@ -505,6 +525,7 @@ module AACMetrics::Metrics
|
|
505
525
|
end
|
506
526
|
# Fallback penalty for missing word
|
507
527
|
effort ||= spelling_effort(word)
|
528
|
+
reffort = effort
|
508
529
|
list_effort += effort
|
509
530
|
|
510
531
|
effort = comp_efforts[word]
|
@@ -513,6 +534,7 @@ module AACMetrics::Metrics
|
|
513
534
|
end
|
514
535
|
effort ||= spelling_effort(word)
|
515
536
|
comp_effort += effort
|
537
|
+
# puts "#{word} - #{reffort.round(1)} - #{effort.round(1)}"
|
516
538
|
end
|
517
539
|
if missing.length > 0
|
518
540
|
# puts "MISSING FROM #{list['id']} (#{missing.length}):"
|
@@ -525,8 +547,10 @@ module AACMetrics::Metrics
|
|
525
547
|
comp_effort_tally += comp_effort
|
526
548
|
res[:cores][list['id']] = {name: list['name'], list: list['words'], average_effort: list_effort, comp_effort: comp_effort}
|
527
549
|
end
|
528
|
-
|
529
|
-
|
550
|
+
res[:care_components][:core] = (target_effort_tally / core_lists.to_a.length) * 5.0
|
551
|
+
target_effort_tally = res[:care_components][:core]
|
552
|
+
res[:care_components][:comp_core] = (comp_effort_tally / core_lists.to_a.length) * 5.0
|
553
|
+
comp_effort_tally = res[:care_components][:comp_core]
|
530
554
|
|
531
555
|
# TODO: Assemble or allow a battery of word combinations,
|
532
556
|
# and calculate the level of effort for each sequence,
|
@@ -574,8 +598,10 @@ module AACMetrics::Metrics
|
|
574
598
|
comp_effort_score = comp_effort_score / words.length
|
575
599
|
res[:sentences] << {sentence: words.join(' '), words: words, effort: target_effort_score, comp_effort: comp_effort_score}
|
576
600
|
end
|
577
|
-
|
578
|
-
|
601
|
+
res[:care_components][:sentences] = res[:sentences].map{|s| s[:effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
|
602
|
+
target_effort_tally += res[:care_components][:sentences]
|
603
|
+
res[:care_components][:comp_sentences] = res[:sentences].map{|s| s[:comp_effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
|
604
|
+
comp_effort_tally += res[:care_components][:comp_sentences]
|
579
605
|
|
580
606
|
res[:fringe_words] = []
|
581
607
|
fringe.each do |word|
|
@@ -586,6 +612,7 @@ module AACMetrics::Metrics
|
|
586
612
|
if !effort
|
587
613
|
synonym_words.each{|w| effort ||= target_efforts[w] }
|
588
614
|
end
|
615
|
+
# puts "!#{word}" unless effort
|
589
616
|
effort ||= spelling_effort(word)
|
590
617
|
target_effort_score += effort
|
591
618
|
|
@@ -597,16 +624,48 @@ module AACMetrics::Metrics
|
|
597
624
|
comp_effort_score += effort
|
598
625
|
res[:fringe_words] << {word: word, effort: target_effort_score, comp_effort: comp_effort_score}
|
599
626
|
end
|
600
|
-
|
601
|
-
|
627
|
+
res[:care_components][:fringe] = res[:fringe_words].map{|s| s[:effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
|
628
|
+
target_effort_tally += res[:care_components][:fringe]
|
629
|
+
res[:care_components][:comp_fringe] = res[:fringe_words].map{|s| s[:comp_effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
|
630
|
+
comp_effort_tally += res[:care_components][:comp_fringe]
|
631
|
+
|
632
|
+
res[:common_fringe_words] = []
|
633
|
+
common_fringe.each do |word|
|
634
|
+
target_effort_score = 0.0
|
635
|
+
comp_effort_score = 0.0
|
636
|
+
synonym_words = [word] + (synonyms[word] || [])
|
637
|
+
effort = target_efforts[word] || target_efforts[word.downcase]
|
638
|
+
if !effort
|
639
|
+
synonym_words.each{|w| effort ||= target_efforts[w] }
|
640
|
+
end
|
641
|
+
effort ||= spelling_effort(word)
|
642
|
+
target_effort_score += effort
|
643
|
+
|
644
|
+
effort = comp_efforts[word] || comp_efforts[word.downcase]
|
645
|
+
if !effort
|
646
|
+
synonym_words.each{|w| effort ||= comp_efforts[w] }
|
647
|
+
end
|
648
|
+
effort ||= spelling_effort(word)
|
649
|
+
comp_effort_score += effort
|
650
|
+
res[:common_fringe_words] << {word: word, effort: target_effort_score, comp_effort: comp_effort_score}
|
651
|
+
end
|
652
|
+
res[:care_components][:common_fringe] = res[:common_fringe_words].map{|s| s[:effort] }.sum.to_f / res[:common_fringe_words].length.to_f * 1.0
|
653
|
+
target_effort_tally += res[:care_components][:common_fringe]
|
654
|
+
res[:care_components][:comp_common_fringe] = res[:common_fringe_words].map{|s| s[:comp_effort] }.sum.to_f / res[:common_fringe_words].length.to_f * 1.0
|
655
|
+
comp_effort_tally += res[:care_components][:comp_common_fringe]
|
602
656
|
|
603
|
-
target_effort_tally +=
|
604
|
-
comp_effort_tally +=
|
657
|
+
target_effort_tally += 70 # placeholder value for future added calculations
|
658
|
+
comp_effort_tally += 70
|
605
659
|
|
660
|
+
# puts target_effort_tally
|
661
|
+
# puts comp_effort_tally
|
662
|
+
# puts (target_effort_tally - comp_effort_tally).abs
|
663
|
+
# puts JSON.pretty_generate(res[:care_components])
|
664
|
+
# raise 'arf'
|
606
665
|
|
607
666
|
|
608
|
-
res[:target_effort_score] = target_effort_tally
|
609
|
-
res[:comp_effort_score] = comp_effort_tally
|
667
|
+
res[:target_effort_score] = [0.0, 350.0 - target_effort_tally].max
|
668
|
+
res[:comp_effort_score] = [0.0, 350.0 - comp_effort_tally].max
|
610
669
|
# puts "CONSIDER MAKING EASIER"
|
611
670
|
res[:high_effort_words] = too_hard
|
612
671
|
# puts too_hard.join(' ')
|