aac-metrics 0.1.8 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 554fc52ede0b5dffdcf9315ec279a9f42a3ef2a44a324195018eda56538336b1
4
- data.tar.gz: 2b082df38edf52ddf495045969db894ef02f7718641658d8d1ca4b012456e14c
3
+ metadata.gz: bddb8e430a21868a5b26312fb5924f36b914446dc212d849330462768fd9b233
4
+ data.tar.gz: c5ddd0e2b835678f0dabf8743099b29d462612d94a4aa4dd261e1cb7337eaa02
5
5
  SHA512:
6
- metadata.gz: 58c3c7e8128b0bee8754baa3b218a36491cf985ed752b917733a0508bc9a4c8abe8c3e2c40ddcb7cd9098bea51a6c3d9143f5ba4cbd2d9098f59f16899bf1e0b
7
- data.tar.gz: c9e2ec540feee357aaf6b1a20b11e5b938d2f4f8d28ba6d03eee80245167b1eb339ab5a2e1440588db6a31cffbe27bee37a44d6ef35f0078f5381d363c06226c
6
+ metadata.gz: 876e09d6be2b2e2b7579c11bb06367296ee7fbba627db0f8d421b4e60d2b7042d9a41433f9b1af10c78a6fc8ac84077170224e059a5a5ba30db6b217cab56936
7
+ data.tar.gz: 5072598db0226690da77985e4e1ed760b24f0d0edc2bc99a5961e59d7f8e8bfa549073f4d0b223559ba48d7d2348556041d8b513944e5427c9c158db3b467f6c
@@ -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
- @@synonyms[locale] = all_words
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]
@@ -1,14 +1,14 @@
1
1
  # TODO:
2
2
  # Qualitative evaluation criteria:
3
- # - this set is easy to learn for communicators
4
- # - this set is easy to learn for supporters
5
- # - the vocabulary organization of this set makes sense
6
- # - this set provides clear opportunities for user-specific words to be added
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
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
- set_pcts[id] = cnt.to_f / obfset.length.to_f
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 += REUSED_CLONE_FROM_OTHER_DISCOUNT * set_pcts[button['clone_id']]
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 += REUSED_SEMANTIC_FROM_OTHER_DISCOUNT * set_pcts[button['semantic_id']]
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
- else
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.6
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.4
332
- REUSED_SEMANTIC_FROM_OTHER_DISCOUNT = 0.0025
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
- target_effort_tally = (target_effort_tally / core_lists.to_a.length) * 5.0
529
- comp_effort_tally = (comp_effort_tally / core_lists.to_a.length) * 5.0
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
- target_effort_tally += res[:sentences].map{|s| s[:effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
578
- comp_effort_tally += res[:sentences].map{|s| s[:comp_effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
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
- target_effort_tally += res[:fringe_words].map{|s| s[:effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
601
- comp_effort_tally += res[:fringe_words].map{|s| s[:comp_effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
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 += 80 # placeholder value for future added calculations
604
- comp_effort_tally += 80
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(' ')