11#!/usr/bin/env ruby
22# frozen_string_literal: true
33
4- require ' bundler/setup'
5- require ' irt_ruby'
6- require ' benchmark'
4+ require " bundler/setup"
5+ require " irt_ruby"
6+ require " benchmark"
77
88# Enhanced model classes that track iterations and convergence
99class TrackedRaschModel < IrtRuby ::RaschModel
1010 attr_reader :iterations , :final_log_likelihood , :convergence_reason
11-
11+
1212 def fit
1313 @iterations = 0
1414 prev_ll = log_likelihood
@@ -31,7 +31,7 @@ def fit
3131 else
3232 ll_diff = ( current_ll - prev_ll ) . abs
3333 @final_log_likelihood = current_ll
34-
34+
3535 if ll_diff < @tolerance && param_delta < @param_tolerance
3636 @convergence_reason = :tolerance_reached
3737 break
@@ -49,14 +49,14 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
4949 # Generate realistic IRT data based on known parameters
5050 true_abilities = Array . new ( num_people ) { rand ( ability_range ) }
5151 true_difficulties = Array . new ( num_items ) { rand ( difficulty_range ) }
52-
52+
5353 data = Array . new ( num_people ) do |person |
5454 Array . new ( num_items ) do |item |
5555 prob = 1.0 / ( 1.0 + Math . exp ( -( true_abilities [ person ] - true_difficulties [ item ] ) ) )
5656 rand < prob ? 1 : 0
5757 end
5858 end
59-
59+
6060 { data : data , true_abilities : true_abilities , true_difficulties : true_difficulties }
6161end
6262
@@ -81,15 +81,15 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
8181
8282tolerance_configs . each do |config |
8383 puts "\n Tolerance: #{ config [ :label ] } "
84-
84+
8585 times = [ ]
8686 iterations = [ ]
8787 convergence_reasons = [ ]
88-
88+
8989 5 . times do
9090 time = Benchmark . measure do
9191 model = TrackedRaschModel . new (
92- data ,
92+ data ,
9393 max_iter : 2000 ,
9494 tolerance : config [ :tolerance ] ,
9595 param_tolerance : config [ :param_tolerance ] ,
@@ -101,17 +101,17 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
101101 end . real
102102 times << time
103103 end
104-
104+
105105 avg_time = times . sum / times . size
106106 avg_iterations = iterations . sum . to_f / iterations . size
107107 convergence_rate = convergence_reasons . count ( :tolerance_reached ) / 5.0
108-
109- printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
108+
109+ printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
110110 avg_time , avg_iterations , convergence_rate * 100 )
111111end
112112
113113# Test convergence with different learning rates
114- puts "\n " + " =" * 70
114+ puts "\n #{ " =" * 70 } "
115115puts "Learning Rate Impact Analysis"
116116puts "-" * 50
117117
@@ -125,12 +125,11 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
125125
126126learning_rate_configs . each do |config |
127127 puts "\n Learning Rate: #{ config [ :label ] } "
128-
128+
129129 times = [ ]
130130 iterations = [ ]
131131 convergence_reasons = [ ]
132- reverts = [ ]
133-
132+
134133 5 . times do
135134 time = Benchmark . measure do
136135 model = TrackedRaschModel . new (
@@ -146,17 +145,17 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
146145 end . real
147146 times << time
148147 end
149-
148+
150149 avg_time = times . sum / times . size
151150 avg_iterations = iterations . sum . to_f / iterations . size
152151 convergence_rate = convergence_reasons . count ( :tolerance_reached ) / 5.0
153-
154- printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
152+
153+ printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
155154 avg_time , avg_iterations , convergence_rate * 100 )
156155end
157156
158157# Test convergence with different dataset characteristics
159- puts "\n " + " =" * 70
158+ puts "\n #{ " =" * 70 } "
160159puts "Dataset Characteristics Impact"
161160puts "-" * 50
162161
@@ -169,19 +168,19 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
169168
170169dataset_configs . each do |config |
171170 puts "\n Dataset: #{ config [ :label ] } "
172-
171+
173172 times = [ ]
174173 iterations = [ ]
175174 convergence_reasons = [ ]
176-
175+
177176 3 . times do
178177 dataset = generate_data (
179- config [ :people ] ,
180- config [ :items ] ,
181- difficulty_range : config [ :diff_range ] ,
178+ config [ :people ] ,
179+ config [ :items ] ,
180+ difficulty_range : config [ :diff_range ] ,
182181 ability_range : config [ :ability_range ]
183182 )
184-
183+
185184 time = Benchmark . measure do
186185 model = TrackedRaschModel . new (
187186 dataset [ :data ] ,
@@ -196,17 +195,17 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
196195 end . real
197196 times << time
198197 end
199-
198+
200199 avg_time = times . sum / times . size
201200 avg_iterations = iterations . sum . to_f / iterations . size
202201 convergence_rate = convergence_reasons . count ( :tolerance_reached ) / 3.0
203-
204- printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
202+
203+ printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
205204 avg_time , avg_iterations , convergence_rate * 100 )
206205end
207206
208207# Test different missing data patterns
209- puts "\n " + " =" * 70
208+ puts "\n #{ " =" * 70 } "
210209puts "Missing Data Pattern Impact"
211210puts "-" * 50
212211
@@ -220,22 +219,22 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
220219
221220missing_configs . each do |config |
222221 puts "\n Missing Data: #{ config [ :label ] } "
223-
222+
224223 # Generate data with missing values
225224 base_data = generate_data ( 100 , 50 ) [ :data ]
226-
227- if config [ :rate ] > 0
228- data_with_missing = base_data . map do |row |
229- row . map { |resp | rand < config [ :rate ] ? nil : resp }
230- end
231- else
232- data_with_missing = base_data
233- end
234-
225+
226+ data_with_missing = if ( config [ :rate ] ) . positive?
227+ base_data . map do |row |
228+ row . map { |resp | rand < config [ :rate ] ? nil : resp }
229+ end
230+ else
231+ base_data
232+ end
233+
235234 times = [ ]
236235 iterations = [ ]
237236 convergence_reasons = [ ]
238-
237+
239238 3 . times do
240239 time = Benchmark . measure do
241240 model = TrackedRaschModel . new (
@@ -252,15 +251,15 @@ def generate_data(num_people, num_items, difficulty_range: (-2..2), ability_rang
252251 end . real
253252 times << time
254253 end
255-
254+
256255 avg_time = times . sum / times . size
257256 avg_iterations = iterations . sum . to_f / iterations . size
258257 convergence_rate = convergence_reasons . count ( :tolerance_reached ) / 3.0
259-
260- printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
258+
259+ printf ( " Time: %6.3fs Iterations: %6.1f Convergence Rate: %4.0f%%\n " ,
261260 avg_time , avg_iterations , convergence_rate * 100 )
262261end
263262
264- puts "\n " + " =" * 70
263+ puts "\n #{ " =" * 70 } "
265264puts "Convergence Analysis Complete!"
266- puts "=" * 70
265+ puts "=" * 70
0 commit comments