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 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(' ')