MDL-41756 (2) quiz statistics : break down question stats by variant
authorJames Pratt <me@jamiep.org>
Sat, 30 Nov 2013 11:50:15 +0000 (18:50 +0700)
committerJames Pratt <me@jamiep.org>
Mon, 27 Jan 2014 11:00:04 +0000 (18:00 +0700)
lib/db/install.xml
lib/db/upgrade.php
mod/quiz/report/statistics/lang/en/quiz_statistics.php
mod/quiz/report/statistics/report.php
mod/quiz/report/statistics/statistics_table.php
mod/quiz/report/statistics/tests/fixtures/mdl_question_states.csv
mod/quiz/report/statistics/tests/statistics_test.php
question/classes/statistics/questions/calculated.php
question/classes/statistics/questions/calculated_for_subquestion.php
question/classes/statistics/questions/calculator.php
version.php

index 99a8360..0166119 100644 (file)
         <FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="slot" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The position in the quiz where this question appears"/>
         <FIELD NAME="subquestion" TYPE="int" LENGTH="4" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="variant" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="s" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="effectiveweight" TYPE="number" LENGTH="15" NOTNULL="false" SEQUENCE="false" DECIMALS="5"/>
         <FIELD NAME="negcovar" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
index 4937628..09a0eea 100644 (file)
@@ -2927,5 +2927,20 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2014011701.00);
     }
 
+    if ($oldversion < 2014012300.01) {
+
+        // Define field variant to be added to question_statistics.
+        $table = new xmldb_table('question_statistics');
+        $field = new xmldb_field('variant', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'subquestion');
+
+        // Conditionally launch add field variant.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2014012300.01);
+    }
+
     return true;
 }
index 0a18886..98f2b93 100644 (file)
@@ -66,6 +66,7 @@ $string['lastattemptsavg'] = 'Average grade of last attempts';
 $string['lastcalculated'] = 'Last calculated {$a->lastcalculated} ago there have been {$a->count} attempts since then.';
 $string['median'] = 'Median grade (for {$a})';
 $string['modelresponse'] = 'Model response';
+$string['nameforvariant'] = 'Variant {$a->variant} of {$a->name}';
 $string['negcovar'] = 'Negative covariance of grade with total attempt grade';
 $string['negcovar_help'] = 'This question\'s grade for this set of attempts on the quiz varies in an opposite way to the overall attempt grade. This means overall attempt grade tends to be below average when the grade for this question is above average and vice-versa.
 
index 4982223..fe09d91 100644 (file)
@@ -412,6 +412,12 @@ class quiz_statistics_report extends quiz_default_report {
         foreach ($questionstats as $questionstat) {
             // Output the data for these question statistics.
             $this->table->add_data_keyed($this->table->format_row($questionstat));
+            if (count($questionstat->variantstats) > 1) {
+                ksort($questionstat->variantstats);
+                foreach ($questionstat->variantstats as $variantstat) {
+                    $this->table->add_data_keyed($this->table->format_row($variantstat));
+                }
+            }
 
             if (empty($questionstat->subquestions)) {
                 continue;
@@ -419,9 +425,21 @@ class quiz_statistics_report extends quiz_default_report {
 
             // And its subquestions, if it has any.
             $subitemstodisplay = explode(',', $questionstat->subquestions);
+            $displayorder = 1;
             foreach ($subitemstodisplay as $subitemid) {
                 $subquestionstats[$subitemid]->maxmark = $questionstat->maxmark;
+                $subquestionstats[$subitemid]->subqdisplayorder = $displayorder;
+                $subquestionstats[$subitemid]->question->number = $questionstat->question->number;
                 $this->table->add_data_keyed($this->table->format_row($subquestionstats[$subitemid]));
+                if (count($subquestionstats[$subitemid]->variantstats) > 1) {
+                    ksort($subquestionstats[$subitemid]->variantstats);
+                    foreach ($subquestionstats[$subitemid]->variantstats as $variantstat) {
+                        $variantstat->subqdisplayorder = $displayorder;
+                        $variantstat->question->number = $questionstat->question->number;
+                        $this->table->add_data_keyed($this->table->format_row($variantstat));
+                    }
+                }
+                $displayorder++;
             }
         }
 
index 73217a5..c295e51 100644 (file)
@@ -136,11 +136,17 @@ class quiz_statistics_table extends flexible_table {
      * @return string contents of this table cell.
      */
     protected function col_number($questionstat) {
+        $number = $questionstat->question->number;
+
         if ($questionstat->subquestion) {
-            return '';
+            $number = $number . '.'.$questionstat->subqdisplayorder;
+        }
+
+        if ($questionstat->question->qtype != 'random' && !is_null($questionstat->variant)) {
+            $number = $number . '.'.$questionstat->variant;
         }
 
-        return $questionstat->question->number;
+        return $number;
     }
 
     /**
@@ -180,6 +186,13 @@ class quiz_statistics_table extends flexible_table {
     protected function col_name($questionstat) {
         $name = $questionstat->question->name;
 
+        if (!is_null($questionstat->variant)) {
+            $a = new stdClass();
+            $a->name = $name;
+            $a->variant = $questionstat->variant;
+            $name = get_string('nameforvariant', 'quiz_statistics', $a);
+        }
+
         if ($this->is_downloading()) {
             return $name;
         }
index 980b607..dec3c2f 100644 (file)
-id,sumgrades,questionid,slot,maxmark,mark
-39872,12,1,1,1,0
-39873,12,2,2,1,0
-39874,12,3,3,1,0
-39875,12,4,4,1,0
-39896,12,5,5,0,0
-39897,12,6,6,0,0
-39898,12,7,7,0,0
-39899,12,8,8,8,5.5
-39900,12,14,9,1,0.3
-39901,12,15,10,1,0.9
-39902,12,16,11,1,1
-39903,12,17,12,1,0.3
-39910,12,18,19,1,0
-39911,12,19,20,1,1
-39908,12,20,17,1,1
-39909,12,21,18,1,0
-39905,12,22,14,1,0
-39906,12,23,15,1,0
-39907,12,24,16,1,1
-39904,12,25,13,1,1
-39992,7.4,1,1,1,0
-39993,7.4,2,2,1,0
-39994,7.4,3,3,1,0
-39995,7.4,4,4,1,0
-40016,7.4,5,5,0,0
-40017,7.4,6,6,0,0
-40018,7.4,7,7,0,0
-40019,7.4,8,8,8,1
-40020,7.4,14,9,1,0.9
-40021,7.4,15,10,1,0.9
-40022,7.4,16,11,1,0.3
-40023,7.4,17,12,1,0.3
-40030,7.4,18,19,1,0
-40031,7.4,19,20,1,1
-40028,7.4,20,17,1,0
-40029,7.4,21,18,1,1
-40025,7.4,22,14,1,0
-40026,7.4,23,15,1,0
-40027,7.4,24,16,1,1
-40024,7.4,25,13,1,1
-40032,11.7,1,1,1,0
-40033,11.7,2,2,1,0
-40034,11.7,3,3,1,0
-40035,11.7,4,4,1,0
-40056,11.7,5,5,0,0
-40057,11.7,6,6,0,0
-40058,11.7,7,7,0,0
-40059,11.7,8,8,8,2.5
-40060,11.7,14,9,1,1
-40061,11.7,15,10,1,0.9
-40062,11.7,16,11,1,0.3
-40063,11.7,17,12,1,1
-40070,11.7,18,19,1,1
-40071,11.7,19,20,1,1
-40068,11.7,20,17,1,1
-40069,11.7,21,18,1,1
-40065,11.7,22,14,1,0
-40066,11.7,23,15,1,1
-40067,11.7,24,16,1,1
-40064,11.7,25,13,1,0
-39352,8.5,1,1,1,0
-39353,8.5,2,2,1,0
-39354,8.5,3,3,1,0
-39355,8.5,4,4,1,0
-39376,8.5,5,5,0,0
-39377,8.5,6,6,0,0
-39378,8.5,7,7,0,0
-39379,8.5,8,8,8,4
-39380,8.5,14,9,1,0.3
-39381,8.5,15,10,1,0.9
-39382,8.5,16,11,1,1
-39383,8.5,17,12,1,0.3
-39390,8.5,18,19,1,0
-39391,8.5,19,20,1,1
-39388,8.5,20,17,1,1
-39389,8.5,21,18,1,0
-39385,8.5,22,14,1,0
-39386,8.5,23,15,1,0
-39387,8.5,24,16,1,0
-39384,8.5,25,13,1,0
-37112,10.1,1,1,1,0
-37113,10.1,2,2,1,0
-37114,10.1,3,3,1,0
-37115,10.1,4,4,1,0
-37136,10.1,5,5,0,0
-37137,10.1,6,6,0,0
-37138,10.1,7,7,0,0
-37139,10.1,8,8,8,3
-37140,10.1,14,9,1,0.9
-37141,10.1,15,10,1,0.3
-37142,10.1,16,11,1,0.9
-37143,10.1,17,12,1,1
-37150,10.1,18,19,1,1
-37151,10.1,19,20,1,0
-37148,10.1,20,17,1,1
-37149,10.1,21,18,1,1
-37145,10.1,22,14,1,1
-37146,10.1,23,15,1,0
-37147,10.1,24,16,1,0
-37144,10.1,25,13,1,0
-37432,11.3,1,1,1,0
-37433,11.3,2,2,1,0
-37434,11.3,3,3,1,0
-37435,11.3,4,4,1,0
-37456,11.3,5,5,0,0
-37457,11.3,6,6,0,0
-37458,11.3,7,7,0,0
-37459,11.3,8,8,8,4.5
-37460,11.3,14,9,1,0.9
-37461,11.3,15,10,1,1
-37462,11.3,16,11,1,1
-37463,11.3,17,12,1,0.9
-37470,11.3,18,19,1,0
-37471,11.3,19,20,1,0
-37468,11.3,20,17,1,0
-37469,11.3,21,18,1,0
-37465,11.3,22,14,1,1
-37466,11.3,23,15,1,1
-37467,11.3,24,16,1,1
-37464,11.3,25,13,1,0
-37472,11.2,1,1,1,0
-37473,11.2,2,2,1,0
-37474,11.2,3,3,1,0
-37475,11.2,4,4,1,0
-37496,11.2,5,5,0,0
-37497,11.2,6,6,0,0
-37498,11.2,7,7,0,0
-37499,11.2,8,8,8,3
-37500,11.2,14,9,1,0.3
-37501,11.2,15,10,1,0.3
-37502,11.2,16,11,1,0.3
-37503,11.2,17,12,1,0.3
-37510,11.2,18,19,1,1
-37511,11.2,19,20,1,1
-37508,11.2,20,17,1,1
-37509,11.2,21,18,1,1
-37505,11.2,22,14,1,0
-37506,11.2,23,15,1,1
-37507,11.2,24,16,1,1
-37504,11.2,25,13,1,1
-37632,14.1,1,1,1,0
-37633,14.1,2,2,1,0
-37634,14.1,3,3,1,0
-37635,14.1,4,4,1,0
-37656,14.1,5,5,0,0
-37657,14.1,6,6,0,0
-37658,14.1,7,7,0,0
-37659,14.1,8,8,8,6
-37660,14.1,14,9,1,0.9
-37661,14.1,15,10,1,0.9
-37662,14.1,16,11,1,1
-37663,14.1,17,12,1,0.3
-37670,14.1,18,19,1,0
-37671,14.1,19,20,1,1
-37668,14.1,20,17,1,1
-37669,14.1,21,18,1,0
-37665,14.1,22,14,1,1
-37666,14.1,23,15,1,1
-37667,14.1,24,16,1,1
-37664,14.1,25,13,1,0
-37672,8.6,1,1,1,0
-37673,8.6,2,2,1,0
-37674,8.6,3,3,1,0
-37675,8.6,4,4,1,0
-37696,8.6,5,5,0,0
-37697,8.6,6,6,0,0
-37698,8.6,7,7,0,0
-37699,8.6,8,8,8,0.5
-37700,8.6,14,9,1,0.9
-37701,8.6,15,10,1,1
-37702,8.6,16,11,1,0.9
-37703,8.6,17,12,1,0.3
-37710,8.6,18,19,1,0
-37711,8.6,19,20,1,1
-37708,8.6,20,17,1,1
-37709,8.6,21,18,1,1
-37705,8.6,22,14,1,1
-37706,8.6,23,15,1,1
-37707,8.6,24,16,1,0
-37704,8.6,25,13,1,0
-37712,11.6,1,1,1,0
-37713,11.6,2,2,1,0
-37714,11.6,3,3,1,0
-37715,11.6,4,4,1,0
-37736,11.6,5,5,0,0
-37737,11.6,6,6,0,0
-37738,11.6,7,7,0,0
-37739,11.6,8,8,8,5.5
-37740,11.6,14,9,1,0.9
-37741,11.6,15,10,1,1
-37742,11.6,16,11,1,0.9
-37743,11.6,17,12,1,0.3
-37750,11.6,18,19,1,0
-37751,11.6,19,20,1,0
-37748,11.6,20,17,1,1
-37749,11.6,21,18,1,0
-37745,11.6,22,14,1,1
-37746,11.6,23,15,1,0
-37747,11.6,24,16,1,0
-37744,11.6,25,13,1,1
-38072,9.3,1,1,1,0
-38073,9.3,2,2,1,0
-38074,9.3,3,3,1,0
-38075,9.3,4,4,1,0
-38096,9.3,5,5,0,0
-38097,9.3,6,6,0,0
-38098,9.3,7,7,0,0
-38099,9.3,8,8,8,2.5
-38100,9.3,14,9,1,0.9
-38101,9.3,15,10,1,1
-38102,9.3,16,11,1,1
-38103,9.3,17,12,1,0.9
-38110,9.3,18,19,1,0
-38111,9.3,19,20,1,1
-38108,9.3,20,17,1,1
-38109,9.3,21,18,1,0
-38105,9.3,22,14,1,1
-38106,9.3,23,15,1,0
-38107,9.3,24,16,1,0
-38104,9.3,25,13,1,0
-38232,13.1,1,1,1,0
-38233,13.1,2,2,1,0
-38234,13.1,3,3,1,0
-38235,13.1,4,4,1,0
-38256,13.1,5,5,0,0
-38257,13.1,6,6,0,0
-38258,13.1,7,7,0,0
-38259,13.1,8,8,8,4
-38260,13.1,14,9,1,0.9
-38261,13.1,15,10,1,0.3
-38262,13.1,16,11,1,0.9
-38263,13.1,17,12,1,1
-38270,13.1,18,19,1,0
-38271,13.1,19,20,1,1
-38268,13.1,20,17,1,1
-38269,13.1,21,18,1,1
-38265,13.1,22,14,1,1
-38266,13.1,23,15,1,1
-38267,13.1,24,16,1,1
-38264,13.1,25,13,1,0
-38272,11.5,1,1,1,0
-38273,11.5,2,2,1,0
-38274,11.5,3,3,1,0
-38275,11.5,4,4,1,0
-38296,11.5,5,5,0,0
-38297,11.5,6,6,0,0
-38298,11.5,7,7,0,0
-38299,11.5,8,8,8,4
-38300,11.5,14,9,1,0.9
-38301,11.5,15,10,1,0.3
-38302,11.5,16,11,1,0.3
-38303,11.5,17,12,1,1
-38310,11.5,18,19,1,1
-38311,11.5,19,20,1,0
-38308,11.5,20,17,1,0
-38309,11.5,21,18,1,1
-38305,11.5,22,14,1,1
-38306,11.5,23,15,1,1
-38307,11.5,24,16,1,0
-38304,11.5,25,13,1,1
-38472,11.3,1,1,1,0
-38473,11.3,2,2,1,0
-38474,11.3,3,3,1,0
-38475,11.3,4,4,1,0
-38496,11.3,5,5,0,0
-38497,11.3,6,6,0,0
-38498,11.3,7,7,0,0
-38499,11.3,8,8,8,3
-38500,11.3,14,9,1,1
-38501,11.3,15,10,1,1
-38502,11.3,16,11,1,0.3
-38503,11.3,17,12,1,1
-38510,11.3,18,19,1,1
-38511,11.3,19,20,1,0
-38508,11.3,20,17,1,1
-38509,11.3,21,18,1,1
-38505,11.3,22,14,1,1
-38506,11.3,23,15,1,0
-38507,11.3,24,16,1,1
-38504,11.3,25,13,1,0
-38632,5.5,1,1,1,0
-38633,5.5,2,2,1,0
-38634,5.5,3,3,1,0
-38635,5.5,4,4,1,0
-38656,5.5,5,5,0,0
-38657,5.5,6,6,0,0
-38658,5.5,7,7,0,0
-38659,5.5,8,8,8,1
-38660,5.5,14,9,1,1
-38661,5.5,15,10,1,0.9
-38662,5.5,16,11,1,0.3
-38663,5.5,17,12,1,0.3
-38670,5.5,18,19,1,0
-38671,5.5,19,20,1,0
-38668,5.5,20,17,1,0
-38669,5.5,21,18,1,0
-38665,5.5,22,14,1,0
-38666,5.5,23,15,1,1
-38667,5.5,24,16,1,0
-38664,5.5,25,13,1,1
-38672,4.8,1,1,1,0
-38673,4.8,2,2,1,0
-38674,4.8,3,3,1,0
-38675,4.8,4,4,1,0
-38696,4.8,5,5,0,0
-38697,4.8,6,6,0,0
-38698,4.8,7,7,0,0
-38699,4.8,8,8,8,1
-38700,4.8,14,9,1,0.3
-38701,4.8,15,10,1,0.3
-38702,4.8,16,11,1,0.3
-38703,4.8,17,12,1,0.9
-38710,4.8,18,19,1,0
-38711,4.8,19,20,1,1
-38708,4.8,20,17,1,0
-38709,4.8,21,18,1,0
-38705,4.8,22,14,1,0
-38706,4.8,23,15,1,0
-38707,4.8,24,16,1,1
-38704,4.8,25,13,1,0
-38992,8.7,1,1,1,0
-38993,8.7,2,2,1,0
-38994,8.7,3,3,1,0
-38995,8.7,4,4,1,0
-39016,8.7,5,5,0,0
-39017,8.7,6,6,0,0
-39018,8.7,7,7,0,0
-39019,8.7,8,8,8,1.5
-39020,8.7,14,9,1,1
-39021,8.7,15,10,1,0.3
-39022,8.7,16,11,1,0.9
-39023,8.7,17,12,1,1
-39030,8.7,18,19,1,0
-39031,8.7,19,20,1,0
-39028,8.7,20,17,1,1
-39029,8.7,21,18,1,0
-39025,8.7,22,14,1,1
-39026,8.7,23,15,1,0
-39027,8.7,24,16,1,1
-39024,8.7,25,13,1,1
-39032,11.8,1,1,1,0
-39033,11.8,2,2,1,0
-39034,11.8,3,3,1,0
-39035,11.8,4,4,1,0
-39056,11.8,5,5,0,0
-39057,11.8,6,6,0,0
-39058,11.8,7,7,0,0
-39059,11.8,8,8,8,4
-39060,11.8,14,9,1,0.9
-39061,11.8,15,10,1,1
-39062,11.8,16,11,1,0.9
-39063,11.8,17,12,1,1
-39070,11.8,18,19,1,0
-39071,11.8,19,20,1,0
-39068,11.8,20,17,1,0
-39069,11.8,21,18,1,1
-39065,11.8,22,14,1,1
-39066,11.8,23,15,1,1
-39067,11.8,24,16,1,1
-39064,11.8,25,13,1,0
-39272,6,1,1,1,0
-39273,6,2,2,1,0
-39274,6,3,3,1,0
-39275,6,4,4,1,0
-39296,6,5,5,0,0
-39297,6,6,6,0,0
-39298,6,7,7,0,0
-39299,6,8,8,8,2
-39300,6,14,9,1,0.9
-39301,6,15,10,1,0.9
-39302,6,16,11,1,0.3
-39303,6,17,12,1,0.9
-39310,6,18,19,1,0
-39311,6,19,20,1,0
-39308,6,20,17,1,0
-39309,6,21,18,1,0
-39305,6,22,14,1,1
-39306,6,23,15,1,0
-39307,6,24,16,1,0
-39304,6,25,13,1,0
-36192,5.9,1,1,1,0
-36193,5.9,2,2,1,0
-36194,5.9,3,3,1,0
-36195,5.9,4,4,1,0
-36216,5.9,5,5,0,0
-36217,5.9,6,6,0,0
-36218,5.9,7,7,0,0
-36219,5.9,8,8,8,1
-36220,5.9,14,9,1,1
-36221,5.9,15,10,1,0.3
-36222,5.9,16,11,1,0.3
-36223,5.9,17,12,1,0.3
-36230,5.9,18,19,1,0
-36231,5.9,19,20,1,0
-36228,5.9,20,17,1,1
-36229,5.9,21,18,1,0
-36225,5.9,22,14,1,1
-36226,5.9,23,15,1,1
-36227,5.9,24,16,1,0
-36224,5.9,25,13,1,0
-36352,12.8,1,1,1,0
-36353,12.8,2,2,1,0
-36354,12.8,3,3,1,0
-36355,12.8,4,4,1,0
-36376,12.8,5,5,0,0
-36377,12.8,6,6,0,0
-36378,12.8,7,7,0,0
-36379,12.8,8,8,8,6
-36380,12.8,14,9,1,0.9
-36381,12.8,15,10,1,1
-36382,12.8,16,11,1,1
-36383,12.8,17,12,1,0.9
-36390,12.8,18,19,1,1
-36391,12.8,19,20,1,1
-36388,12.8,20,17,1,0
-36389,12.8,21,18,1,0
-36385,12.8,22,14,1,0
-36386,12.8,23,15,1,0
-36387,12.8,24,16,1,1
-36384,12.8,25,13,1,0
-36832,13.8,1,1,1,0
-36833,13.8,2,2,1,0
-36834,13.8,3,3,1,0
-36835,13.8,4,4,1,0
-36856,13.8,5,5,0,0
-36857,13.8,6,6,0,0
-36858,13.8,7,7,0,0
-36859,13.8,8,8,8,7
-36860,13.8,14,9,1,0.9
-36861,13.8,15,10,1,0.3
-36862,13.8,16,11,1,0.3
-36863,13.8,17,12,1,0.3
-36870,13.8,18,19,1,0
-36871,13.8,19,20,1,0
-36868,13.8,20,17,1,1
-36869,13.8,21,18,1,1
-36865,13.8,22,14,1,0
-36866,13.8,23,15,1,1
-36867,13.8,24,16,1,1
-36864,13.8,25,13,1,1
+id,sumgrades,questionid,slot,maxmark,mark,variant
+39872,12,1,1,1,0,1
+39873,12,2,2,1,0,1
+39874,12,3,3,1,0,1
+39875,12,4,4,1,0,1
+39896,12,5,5,0,0,1
+39897,12,6,6,0,0,1
+39898,12,7,7,0,0,1
+39899,12,8,8,8,5.5,1
+39900,12,14,9,1,0.3,1
+39901,12,15,10,1,0.9,1
+39902,12,16,11,1,1,1
+39903,12,17,12,1,0.3,1
+39910,12,18,19,1,0,1
+39911,12,19,20,1,1,1
+39908,12,20,17,1,1,1
+39909,12,21,18,1,0,1
+39905,12,22,14,1,0,1
+39906,12,23,15,1,0,1
+39907,12,24,16,1,1,1
+39904,12,25,13,1,1,1
+39992,7.4,1,1,1,0,1
+39993,7.4,2,2,1,0,1
+39994,7.4,3,3,1,0,1
+39995,7.4,4,4,1,0,1
+40016,7.4,5,5,0,0,1
+40017,7.4,6,6,0,0,1
+40018,7.4,7,7,0,0,1
+40019,7.4,8,8,8,1,1
+40020,7.4,14,9,1,0.9,1
+40021,7.4,15,10,1,0.9,1
+40022,7.4,16,11,1,0.3,1
+40023,7.4,17,12,1,0.3,1
+40030,7.4,18,19,1,0,1
+40031,7.4,19,20,1,1,1
+40028,7.4,20,17,1,0,1
+40029,7.4,21,18,1,1,1
+40025,7.4,22,14,1,0,1
+40026,7.4,23,15,1,0,1
+40027,7.4,24,16,1,1,1
+40024,7.4,25,13,1,1,1
+40032,11.7,1,1,1,0,1
+40033,11.7,2,2,1,0,1
+40034,11.7,3,3,1,0,1
+40035,11.7,4,4,1,0,1
+40056,11.7,5,5,0,0,1
+40057,11.7,6,6,0,0,1
+40058,11.7,7,7,0,0,1
+40059,11.7,8,8,8,2.5,1
+40060,11.7,14,9,1,1,1
+40061,11.7,15,10,1,0.9,1
+40062,11.7,16,11,1,0.3,1
+40063,11.7,17,12,1,1,1
+40070,11.7,18,19,1,1,1
+40071,11.7,19,20,1,1,1
+40068,11.7,20,17,1,1,1
+40069,11.7,21,18,1,1,1
+40065,11.7,22,14,1,0,1
+40066,11.7,23,15,1,1,1
+40067,11.7,24,16,1,1,1
+40064,11.7,25,13,1,0,1
+39352,8.5,1,1,1,0,1
+39353,8.5,2,2,1,0,1
+39354,8.5,3,3,1,0,1
+39355,8.5,4,4,1,0,1
+39376,8.5,5,5,0,0,1
+39377,8.5,6,6,0,0,1
+39378,8.5,7,7,0,0,1
+39379,8.5,8,8,8,4,1
+39380,8.5,14,9,1,0.3,1
+39381,8.5,15,10,1,0.9,1
+39382,8.5,16,11,1,1,1
+39383,8.5,17,12,1,0.3,1
+39390,8.5,18,19,1,0,1
+39391,8.5,19,20,1,1,1
+39388,8.5,20,17,1,1,1
+39389,8.5,21,18,1,0,1
+39385,8.5,22,14,1,0,1
+39386,8.5,23,15,1,0,1
+39387,8.5,24,16,1,0,1
+39384,8.5,25,13,1,0,1
+37112,10.1,1,1,1,0,1
+37113,10.1,2,2,1,0,1
+37114,10.1,3,3,1,0,1
+37115,10.1,4,4,1,0,1
+37136,10.1,5,5,0,0,1
+37137,10.1,6,6,0,0,1
+37138,10.1,7,7,0,0,1
+37139,10.1,8,8,8,3,1
+37140,10.1,14,9,1,0.9,1
+37141,10.1,15,10,1,0.3,1
+37142,10.1,16,11,1,0.9,1
+37143,10.1,17,12,1,1,1
+37150,10.1,18,19,1,1,1
+37151,10.1,19,20,1,0,1
+37148,10.1,20,17,1,1,1
+37149,10.1,21,18,1,1,1
+37145,10.1,22,14,1,1,1
+37146,10.1,23,15,1,0,1
+37147,10.1,24,16,1,0,1
+37144,10.1,25,13,1,0,1
+37432,11.3,1,1,1,0,1
+37433,11.3,2,2,1,0,1
+37434,11.3,3,3,1,0,1
+37435,11.3,4,4,1,0,1
+37456,11.3,5,5,0,0,1
+37457,11.3,6,6,0,0,1
+37458,11.3,7,7,0,0,1
+37459,11.3,8,8,8,4.5,1
+37460,11.3,14,9,1,0.9,1
+37461,11.3,15,10,1,1,1
+37462,11.3,16,11,1,1,1
+37463,11.3,17,12,1,0.9,1
+37470,11.3,18,19,1,0,1
+37471,11.3,19,20,1,0,1
+37468,11.3,20,17,1,0,1
+37469,11.3,21,18,1,0,1
+37465,11.3,22,14,1,1,1
+37466,11.3,23,15,1,1,1
+37467,11.3,24,16,1,1,1
+37464,11.3,25,13,1,0,1
+37472,11.2,1,1,1,0,1
+37473,11.2,2,2,1,0,1
+37474,11.2,3,3,1,0,1
+37475,11.2,4,4,1,0,1
+37496,11.2,5,5,0,0,1
+37497,11.2,6,6,0,0,1
+37498,11.2,7,7,0,0,1
+37499,11.2,8,8,8,3,1
+37500,11.2,14,9,1,0.3,1
+37501,11.2,15,10,1,0.3,1
+37502,11.2,16,11,1,0.3,1
+37503,11.2,17,12,1,0.3,1
+37510,11.2,18,19,1,1,1
+37511,11.2,19,20,1,1,1
+37508,11.2,20,17,1,1,1
+37509,11.2,21,18,1,1,1
+37505,11.2,22,14,1,0,1
+37506,11.2,23,15,1,1,1
+37507,11.2,24,16,1,1,1
+37504,11.2,25,13,1,1,1
+37632,14.1,1,1,1,0,1
+37633,14.1,2,2,1,0,1
+37634,14.1,3,3,1,0,1
+37635,14.1,4,4,1,0,1
+37656,14.1,5,5,0,0,1
+37657,14.1,6,6,0,0,1
+37658,14.1,7,7,0,0,1
+37659,14.1,8,8,8,6,1
+37660,14.1,14,9,1,0.9,1
+37661,14.1,15,10,1,0.9,1
+37662,14.1,16,11,1,1,1
+37663,14.1,17,12,1,0.3,1
+37670,14.1,18,19,1,0,1
+37671,14.1,19,20,1,1,1
+37668,14.1,20,17,1,1,1
+37669,14.1,21,18,1,0,1
+37665,14.1,22,14,1,1,1
+37666,14.1,23,15,1,1,1
+37667,14.1,24,16,1,1,1
+37664,14.1,25,13,1,0,1
+37672,8.6,1,1,1,0,1
+37673,8.6,2,2,1,0,1
+37674,8.6,3,3,1,0,1
+37675,8.6,4,4,1,0,1
+37696,8.6,5,5,0,0,1
+37697,8.6,6,6,0,0,1
+37698,8.6,7,7,0,0,1
+37699,8.6,8,8,8,0.5,1
+37700,8.6,14,9,1,0.9,1
+37701,8.6,15,10,1,1,1
+37702,8.6,16,11,1,0.9,1
+37703,8.6,17,12,1,0.3,1
+37710,8.6,18,19,1,0,1
+37711,8.6,19,20,1,1,1
+37708,8.6,20,17,1,1,1
+37709,8.6,21,18,1,1,1
+37705,8.6,22,14,1,1,1
+37706,8.6,23,15,1,1,1
+37707,8.6,24,16,1,0,1
+37704,8.6,25,13,1,0,1
+37712,11.6,1,1,1,0,1
+37713,11.6,2,2,1,0,1
+37714,11.6,3,3,1,0,1
+37715,11.6,4,4,1,0,1
+37736,11.6,5,5,0,0,1
+37737,11.6,6,6,0,0,1
+37738,11.6,7,7,0,0,1
+37739,11.6,8,8,8,5.5,1
+37740,11.6,14,9,1,0.9,1
+37741,11.6,15,10,1,1,1
+37742,11.6,16,11,1,0.9,1
+37743,11.6,17,12,1,0.3,1
+37750,11.6,18,19,1,0,1
+37751,11.6,19,20,1,0,1
+37748,11.6,20,17,1,1,1
+37749,11.6,21,18,1,0,1
+37745,11.6,22,14,1,1,1
+37746,11.6,23,15,1,0,1
+37747,11.6,24,16,1,0,1
+37744,11.6,25,13,1,1,1
+38072,9.3,1,1,1,0,1
+38073,9.3,2,2,1,0,1
+38074,9.3,3,3,1,0,1
+38075,9.3,4,4,1,0,1
+38096,9.3,5,5,0,0,1
+38097,9.3,6,6,0,0,1
+38098,9.3,7,7,0,0,1
+38099,9.3,8,8,8,2.5,1
+38100,9.3,14,9,1,0.9,1
+38101,9.3,15,10,1,1,1
+38102,9.3,16,11,1,1,1
+38103,9.3,17,12,1,0.9,1
+38110,9.3,18,19,1,0,1
+38111,9.3,19,20,1,1,1
+38108,9.3,20,17,1,1,1
+38109,9.3,21,18,1,0,1
+38105,9.3,22,14,1,1,1
+38106,9.3,23,15,1,0,1
+38107,9.3,24,16,1,0,1
+38104,9.3,25,13,1,0,1
+38232,13.1,1,1,1,0,1
+38233,13.1,2,2,1,0,1
+38234,13.1,3,3,1,0,1
+38235,13.1,4,4,1,0,1
+38256,13.1,5,5,0,0,1
+38257,13.1,6,6,0,0,1
+38258,13.1,7,7,0,0,1
+38259,13.1,8,8,8,4,1
+38260,13.1,14,9,1,0.9,1
+38261,13.1,15,10,1,0.3,1
+38262,13.1,16,11,1,0.9,1
+38263,13.1,17,12,1,1,1
+38270,13.1,18,19,1,0,1
+38271,13.1,19,20,1,1,1
+38268,13.1,20,17,1,1,1
+38269,13.1,21,18,1,1,1
+38265,13.1,22,14,1,1,1
+38266,13.1,23,15,1,1,1
+38267,13.1,24,16,1,1,1
+38264,13.1,25,13,1,0,1
+38272,11.5,1,1,1,0,1
+38273,11.5,2,2,1,0,1
+38274,11.5,3,3,1,0,1
+38275,11.5,4,4,1,0,1
+38296,11.5,5,5,0,0,1
+38297,11.5,6,6,0,0,1
+38298,11.5,7,7,0,0,1
+38299,11.5,8,8,8,4,1
+38300,11.5,14,9,1,0.9,1
+38301,11.5,15,10,1,0.3,1
+38302,11.5,16,11,1,0.3,1
+38303,11.5,17,12,1,1,1
+38310,11.5,18,19,1,1,1
+38311,11.5,19,20,1,0,1
+38308,11.5,20,17,1,0,1
+38309,11.5,21,18,1,1,1
+38305,11.5,22,14,1,1,1
+38306,11.5,23,15,1,1,1
+38307,11.5,24,16,1,0,1
+38304,11.5,25,13,1,1,1
+38472,11.3,1,1,1,0,1
+38473,11.3,2,2,1,0,1
+38474,11.3,3,3,1,0,1
+38475,11.3,4,4,1,0,1
+38496,11.3,5,5,0,0,1
+38497,11.3,6,6,0,0,1
+38498,11.3,7,7,0,0,1
+38499,11.3,8,8,8,3,1
+38500,11.3,14,9,1,1,1
+38501,11.3,15,10,1,1,1
+38502,11.3,16,11,1,0.3,1
+38503,11.3,17,12,1,1,1
+38510,11.3,18,19,1,1,1
+38511,11.3,19,20,1,0,1
+38508,11.3,20,17,1,1,1
+38509,11.3,21,18,1,1,1
+38505,11.3,22,14,1,1,1
+38506,11.3,23,15,1,0,1
+38507,11.3,24,16,1,1,1
+38504,11.3,25,13,1,0,1
+38632,5.5,1,1,1,0,1
+38633,5.5,2,2,1,0,1
+38634,5.5,3,3,1,0,1
+38635,5.5,4,4,1,0,1
+38656,5.5,5,5,0,0,1
+38657,5.5,6,6,0,0,1
+38658,5.5,7,7,0,0,1
+38659,5.5,8,8,8,1,1
+38660,5.5,14,9,1,1,1
+38661,5.5,15,10,1,0.9,1
+38662,5.5,16,11,1,0.3,1
+38663,5.5,17,12,1,0.3,1
+38670,5.5,18,19,1,0,1
+38671,5.5,19,20,1,0,1
+38668,5.5,20,17,1,0,1
+38669,5.5,21,18,1,0,1
+38665,5.5,22,14,1,0,1
+38666,5.5,23,15,1,1,1
+38667,5.5,24,16,1,0,1
+38664,5.5,25,13,1,1,1
+38672,4.8,1,1,1,0,1
+38673,4.8,2,2,1,0,1
+38674,4.8,3,3,1,0,1
+38675,4.8,4,4,1,0,1
+38696,4.8,5,5,0,0,1
+38697,4.8,6,6,0,0,1
+38698,4.8,7,7,0,0,1
+38699,4.8,8,8,8,1,1
+38700,4.8,14,9,1,0.3,1
+38701,4.8,15,10,1,0.3,1
+38702,4.8,16,11,1,0.3,1
+38703,4.8,17,12,1,0.9,1
+38710,4.8,18,19,1,0,1
+38711,4.8,19,20,1,1,1
+38708,4.8,20,17,1,0,1
+38709,4.8,21,18,1,0,1
+38705,4.8,22,14,1,0,1
+38706,4.8,23,15,1,0,1
+38707,4.8,24,16,1,1,1
+38704,4.8,25,13,1,0,1
+38992,8.7,1,1,1,0,1
+38993,8.7,2,2,1,0,1
+38994,8.7,3,3,1,0,1
+38995,8.7,4,4,1,0,1
+39016,8.7,5,5,0,0,1
+39017,8.7,6,6,0,0,1
+39018,8.7,7,7,0,0,1
+39019,8.7,8,8,8,1.5,1
+39020,8.7,14,9,1,1,1
+39021,8.7,15,10,1,0.3,1
+39022,8.7,16,11,1,0.9,1
+39023,8.7,17,12,1,1,1
+39030,8.7,18,19,1,0,1
+39031,8.7,19,20,1,0,1
+39028,8.7,20,17,1,1,1
+39029,8.7,21,18,1,0,1
+39025,8.7,22,14,1,1,1
+39026,8.7,23,15,1,0,1
+39027,8.7,24,16,1,1,1
+39024,8.7,25,13,1,1,1
+39032,11.8,1,1,1,0,1
+39033,11.8,2,2,1,0,1
+39034,11.8,3,3,1,0,1
+39035,11.8,4,4,1,0,1
+39056,11.8,5,5,0,0,1
+39057,11.8,6,6,0,0,1
+39058,11.8,7,7,0,0,1
+39059,11.8,8,8,8,4,1
+39060,11.8,14,9,1,0.9,1
+39061,11.8,15,10,1,1,1
+39062,11.8,16,11,1,0.9,1
+39063,11.8,17,12,1,1,1
+39070,11.8,18,19,1,0,1
+39071,11.8,19,20,1,0,1
+39068,11.8,20,17,1,0,1
+39069,11.8,21,18,1,1,1
+39065,11.8,22,14,1,1,1
+39066,11.8,23,15,1,1,1
+39067,11.8,24,16,1,1,1
+39064,11.8,25,13,1,0,1
+39272,6,1,1,1,0,1
+39273,6,2,2,1,0,1
+39274,6,3,3,1,0,1
+39275,6,4,4,1,0,1
+39296,6,5,5,0,0,1
+39297,6,6,6,0,0,1
+39298,6,7,7,0,0,1
+39299,6,8,8,8,2,1
+39300,6,14,9,1,0.9,1
+39301,6,15,10,1,0.9,1
+39302,6,16,11,1,0.3,1
+39303,6,17,12,1,0.9,1
+39310,6,18,19,1,0,1
+39311,6,19,20,1,0,1
+39308,6,20,17,1,0,1
+39309,6,21,18,1,0,1
+39305,6,22,14,1,1,1
+39306,6,23,15,1,0,1
+39307,6,24,16,1,0,1
+39304,6,25,13,1,0,1
+36192,5.9,1,1,1,0,1
+36193,5.9,2,2,1,0,1
+36194,5.9,3,3,1,0,1
+36195,5.9,4,4,1,0,1
+36216,5.9,5,5,0,0,1
+36217,5.9,6,6,0,0,1
+36218,5.9,7,7,0,0,1
+36219,5.9,8,8,8,1,1
+36220,5.9,14,9,1,1,1
+36221,5.9,15,10,1,0.3,1
+36222,5.9,16,11,1,0.3,1
+36223,5.9,17,12,1,0.3,1
+36230,5.9,18,19,1,0,1
+36231,5.9,19,20,1,0,1
+36228,5.9,20,17,1,1,1
+36229,5.9,21,18,1,0,1
+36225,5.9,22,14,1,1,1
+36226,5.9,23,15,1,1,1
+36227,5.9,24,16,1,0,1
+36224,5.9,25,13,1,0,1
+36352,12.8,1,1,1,0,1
+36353,12.8,2,2,1,0,1
+36354,12.8,3,3,1,0,1
+36355,12.8,4,4,1,0,1
+36376,12.8,5,5,0,0,1
+36377,12.8,6,6,0,0,1
+36378,12.8,7,7,0,0,1
+36379,12.8,8,8,8,6,1
+36380,12.8,14,9,1,0.9,1
+36381,12.8,15,10,1,1,1
+36382,12.8,16,11,1,1,1
+36383,12.8,17,12,1,0.9,1
+36390,12.8,18,19,1,1,1
+36391,12.8,19,20,1,1,1
+36388,12.8,20,17,1,0,1
+36389,12.8,21,18,1,0,1
+36385,12.8,22,14,1,0,1
+36386,12.8,23,15,1,0,1
+36387,12.8,24,16,1,1,1
+36384,12.8,25,13,1,0,1
+36832,13.8,1,1,1,0,1
+36833,13.8,2,2,1,0,1
+36834,13.8,3,3,1,0,1
+36835,13.8,4,4,1,0,1
+36856,13.8,5,5,0,0,1
+36857,13.8,6,6,0,0,1
+36858,13.8,7,7,0,0,1
+36859,13.8,8,8,8,7,1
+36860,13.8,14,9,1,0.9,1
+36861,13.8,15,10,1,0.3,1
+36862,13.8,16,11,1,0.3,1
+36863,13.8,17,12,1,0.3,1
+36870,13.8,18,19,1,0,1
+36871,13.8,19,20,1,0,1
+36868,13.8,20,17,1,1,1
+36869,13.8,21,18,1,1,1
+36865,13.8,22,14,1,0,1
+36866,13.8,23,15,1,1,1
+36867,13.8,24,16,1,1,1
+36864,13.8,25,13,1,1,1
index e4dd8ac..6ba5284 100644 (file)
@@ -130,10 +130,10 @@ class quiz_statistics_question_stats_testcase extends basic_testcase {
         foreach ($this->qstats as $qstat) {
             $value = array_shift($values);
             if ($value !== null) {
-                $this->assertEquals($qstat->{$fieldname} * $multiplier,
-                    $value, '', 1E-6);
+                $this->assertEquals($value, $qstat->{$fieldname} * $multiplier,
+                    '', 1E-6);
             } else {
-                $this->assertEquals($qstat->{$fieldname} * $multiplier, $value);
+                $this->assertEquals($value, $qstat->{$fieldname} * $multiplier);
             }
         }
     }
index 6af6aae..3d8b652 100644 (file)
@@ -44,6 +44,12 @@ class calculated {
 
     public $slot = null;
 
+    /**
+     * @var null|integer if this property is not null then this is the stats for a variant of a question or when inherited by
+     *                   calculated_for_subquestion and not null then this is the stats for a variant of a sub question.
+     */
+    public $variant = null;
+
     /**
      * @var bool is this a sub question.
      */
@@ -103,7 +109,7 @@ class calculated {
     // End of fields in db.
 
     protected $fieldsindb = array('questionid', 'slot', 'subquestion', 's', 'effectiveweight', 'negcovar', 'discriminationindex',
-        'discriminativeefficiency', 'sd', 'facility', 'subquestions', 'maxmark', 'positions', 'randomguessscore');
+        'discriminativeefficiency', 'sd', 'facility', 'subquestions', 'maxmark', 'positions', 'randomguessscore', 'variant');
 
     // Fields used for intermediate calculations.
 
@@ -152,6 +158,14 @@ class calculated {
      */
     public $question;
 
+    /**
+     * An array of calculated stats for each variant of the question. Even when there is just one variant we still calculate this
+     * data as there is no way to know if there are variants before we have finished going through the attempt data one time.
+     *
+     * @var calculated[] $variants
+     */
+    public $variantstats = array();
+
     /**
      * Set if this record has been retrieved from cache. This is the time that the statistics were calculated.
      *
@@ -173,6 +187,12 @@ class calculated {
             $toinsert->{$field} = $this->{$field};
         }
         $DB->insert_record('question_statistics', $toinsert, false);
+
+        if (count($this->variantstats) > 1) {
+            foreach ($this->variantstats as $variantstat) {
+                $variantstat->cache($qubaids);
+            }
+        }
     }
 
     /**
index 061cc96..de740eb 100644 (file)
@@ -34,4 +34,9 @@ class calculated_for_subquestion extends calculated {
     public $differentweights = false;
 
     public $negcovar = 0;
+
+    /**
+     * @var int only set immediately before display in the table. The order of display in the table.
+     */
+    public $subqdisplayorder;
 }
index cf376aa..940903f 100644 (file)
@@ -73,16 +73,41 @@ class calculator {
         $this->progress = $progress;
 
         foreach ($questions as $slot => $question) {
-            $this->questionstats[$slot] = new calculated();
-            $this->questionstats[$slot]->questionid = $question->id;
-            $this->questionstats[$slot]->question = $question;
-            $this->questionstats[$slot]->slot = $slot;
-            $this->questionstats[$slot]->positions = $question->number;
-            $this->questionstats[$slot]->maxmark = $question->maxmark;
-            $this->questionstats[$slot]->randomguessscore = $this->get_random_guess_score($question);
+            $this->questionstats[$slot] = $this->new_slot_stats($question, $slot);
         }
     }
 
+    /**
+     * Set up a calculated instance ready to store a questions stats.
+     *
+     * @param $question
+     * @param $slot
+     * @return calculated
+     */
+    protected function new_slot_stats($question, $slot) {
+        $toreturn = new calculated();
+        $toreturn->questionid = $question->id;
+        $toreturn->maxmark = $question->maxmark;
+        $toreturn->question = $question;
+        $toreturn->slot = $slot;
+        $toreturn->positions = $question->number;
+        $toreturn->randomguessscore = $this->get_random_guess_score($question);
+        return $toreturn;
+    }
+
+    /**
+     * Set up a calculated instance ready to store a randomly selected question's stats.
+     *
+     * @param $step
+     * @return calculated_for_subquestion
+     */
+    protected function new_subq_stats($step) {
+        $toreturn = new calculated_for_subquestion();
+        $toreturn->questionid = $step->questionid;
+        $toreturn->maxmark = $step->maxmark;
+        return $toreturn;
+    }
+
     /**
      * @param $qubaids \qubaid_condition
      * @return array containing two arrays calculated[] and calculated_for_subquestion[].
@@ -98,21 +123,39 @@ class calculator {
             // Compute the statistics of position, and for random questions, work
             // out which questions appear in which positions.
             foreach ($lateststeps as $step) {
+
                 $this->progress->increment_progress();
-                $this->initial_steps_walker($step, $this->questionstats[$step->slot], $summarks);
 
-                // If this is a random question what is the real item being used?
-                if ($step->questionid != $this->questionstats[$step->slot]->questionid) {
+                $israndomquestion = ($step->questionid != $this->questionstats[$step->slot]->questionid);
+                // If this is a variant we have not seen before create a place to store stats calculations for this variant.
+                if (!$israndomquestion && !isset($this->questionstats[$step->slot]->variantstats[$step->variant])) {
+                    $this->questionstats[$step->slot]->variantstats[$step->variant] =
+                        $this->new_slot_stats($this->questionstats[$step->slot]->question, $step->slot);
+                    $this->questionstats[$step->slot]->variantstats[$step->variant]->variant = $step->variant;
+                }
+
+
+                // Step data walker for main question.
+                $this->initial_steps_walker($step, $this->questionstats[$step->slot], $summarks, true, !$israndomquestion);
+
+                // If this is a random question do the calculations for sub question stats.
+                if ($israndomquestion) {
                     if (!isset($this->subquestionstats[$step->questionid])) {
-                        $this->subquestionstats[$step->questionid] = new calculated_for_subquestion();
-                        $this->subquestionstats[$step->questionid]->questionid = $step->questionid;
-                        $this->subquestionstats[$step->questionid]->maxmark = $step->maxmark;
+                        $this->subquestionstats[$step->questionid] = $this->new_subq_stats($step);
                     } else if ($this->subquestionstats[$step->questionid]->maxmark != $step->maxmark) {
                         $this->subquestionstats[$step->questionid]->differentweights = true;
                     }
 
+                    // If this is a variant of this subq we have not seen before create a place to store stats calculations for it.
+                    if (!isset($this->subquestionstats[$step->questionid]->variantstats[$step->variant])) {
+                        $this->subquestionstats[$step->questionid]->variantstats[$step->variant] = $this->new_subq_stats($step);
+                        $this->subquestionstats[$step->questionid]->variantstats[$step->variant]->variant = $step->variant;
+                    }
+
                     $this->initial_steps_walker($step, $this->subquestionstats[$step->questionid], $summarks, false);
 
+                    // Extra stuff we need to do in this loop for subqs to keep track of where they need to be displayed later.
+
                     $number = $this->questionstats[$step->slot]->question->number;
                     $this->subquestionstats[$step->questionid]->usedin[$number] = $number;
 
@@ -137,10 +180,15 @@ class calculator {
             $this->progress->start_progress('', count($subquestions), 1);
             foreach ($subquestions as $qid => $subquestion) {
                 $this->progress->increment_progress();
+                $subquestion->maxmark = $this->subquestionstats[$qid]->maxmark;
                 $this->subquestionstats[$qid]->question = $subquestion;
-                $this->subquestionstats[$qid]->question->maxmark = $this->subquestionstats[$qid]->maxmark;
                 $this->subquestionstats[$qid]->randomguessscore = $this->get_random_guess_score($subquestion);
 
+                foreach ($this->subquestionstats[$qid]->variantstats as $variantstat) {
+                    $variantstat->question = $subquestion;
+                    $variantstat->randomguessscore = $this->get_random_guess_score($subquestion);
+                }
+
                 $this->initial_question_walker($this->subquestionstats[$qid]);
 
                 if ($this->subquestionstats[$qid]->differentweights) {
@@ -168,12 +216,13 @@ class calculator {
             // foreach ($this->questions as $qid => $question).
             reset($this->questionstats);
             $this->progress->start_progress('', count($this->questionstats), 1);
-            while (list($slot, $questionstat) = each($this->questionstats)) {
+            while (list(, $questionstat) = each($this->questionstats)) {
                 $this->progress->increment_progress();
                 $nextquestionstats = current($this->questionstats);
 
                 $this->initial_question_walker($questionstat);
 
+                // The rest of this loop is again to work out where randomly selected question stats should be displayed.
                 if ($questionstat->question->qtype == 'random') {
                     $randomselectorstring = $questionstat->question->category .'/'. $questionstat->question->questiontext;
                     if ($nextquestionstats && $nextquestionstats->question->qtype == 'random') {
@@ -194,7 +243,8 @@ class calculator {
             $this->progress->start_progress('', count($lateststeps), 1);
             foreach ($lateststeps as $step) {
                 $this->progress->increment_progress();
-                $this->secondary_steps_walker($step, $this->questionstats[$step->slot], $summarks);
+                $israndomquestion = ($this->questionstats[$step->slot]->question->qtype == 'random');
+                $this->secondary_steps_walker($step, $this->questionstats[$step->slot], $summarks, !$israndomquestion);
 
                 if ($this->questionstats[$step->slot]->subquestions) {
                     $this->secondary_steps_walker($step, $this->subquestionstats[$step->questionid], $summarks);
@@ -257,19 +307,36 @@ class calculator {
 
         $questionids = array();
         foreach ($questionstatrecs as $fromdb) {
-            if (!$fromdb->slot) {
+            if (is_null($fromdb->variant) && !$fromdb->slot) {
                 $questionids[] = $fromdb->questionid;
             }
         }
         $subquestions = question_load_questions($questionids);
         foreach ($questionstatrecs as $fromdb) {
-            if ($fromdb->slot) {
-                $this->questionstats[$fromdb->slot]->populate_from_record($fromdb);
-                // Array created in constructor and populated from question.
-            } else {
-                $this->subquestionstats[$fromdb->questionid] = new calculated_for_subquestion();
-                $this->subquestionstats[$fromdb->questionid]->populate_from_record($fromdb);
-                $this->subquestionstats[$fromdb->questionid]->question = $subquestions[$fromdb->questionid];
+            if (is_null($fromdb->variant)) {
+                if ($fromdb->slot) {
+                    $this->questionstats[$fromdb->slot]->populate_from_record($fromdb);
+                    // Array created in constructor and populated from question.
+                } else {
+                    $this->subquestionstats[$fromdb->questionid] = new calculated_for_subquestion();
+                    $this->subquestionstats[$fromdb->questionid]->populate_from_record($fromdb);
+                    $this->subquestionstats[$fromdb->questionid]->question = $subquestions[$fromdb->questionid];
+                }
+            }
+        }
+        // Add cached variant stats to data structure.
+        foreach ($questionstatrecs as $fromdb) {
+            if (!is_null($fromdb->variant)) {
+                if ($fromdb->slot) {
+                    $newcalcinstance = new calculated();
+                    $this->questionstats[$fromdb->slot]->variantstats[$fromdb->variant] = $newcalcinstance;
+                    $newcalcinstance->question = $this->questionstats[$fromdb->slot]->question;
+                } else {
+                    $newcalcinstance = new calculated_for_subquestion();
+                    $this->subquestionstats[$fromdb->questionid]->variantstats[$fromdb->variant] = $newcalcinstance;
+                    $newcalcinstance->question = $subquestions[$fromdb->questionid];
+                }
+                $newcalcinstance->populate_from_record($fromdb);
             }
         }
         return array($this->questionstats, $this->subquestionstats);
@@ -313,6 +380,7 @@ class calculator {
         $fields = "    qas.id,
     qa.questionusageid,
     qa.questionid,
+    qa.variant,
     qa.slot,
     qa.maxmark,
     qas.fraction * qa.maxmark as mark";
@@ -335,12 +403,13 @@ class calculator {
      * Update $stats->totalmarks, $stats->markarray, $stats->totalothermarks
      * and $stats->othermarksarray to include another state.
      *
-     * @param object $step         the state to add to the statistics.
+     * @param object     $step         the state to add to the statistics.
      * @param calculated $stats        the question statistics we are accumulating.
-     * @param array  $summarks     of the sum of marks for each question usage, indexed by question usage id
-     * @param bool   $positionstat whether this is a statistic of position of question.
+     * @param array      $summarks     of the sum of marks for each question usage, indexed by question usage id
+     * @param bool       $positionstat whether this is a statistic of position of question.
+     * @param bool       $dovariantalso do we also want to do the same calculations for this variant?
      */
-    protected function initial_steps_walker($step, $stats, $summarks, $positionstat = true) {
+    protected function initial_steps_walker($step, $stats, $summarks, $positionstat = true, $dovariantalso = true) {
         $stats->s++;
         $stats->totalmarks += $step->mark;
         $stats->markarray[] = $step->mark;
@@ -353,15 +422,20 @@ class calculator {
             $stats->totalothermarks += $summarks[$step->questionusageid];
             $stats->othermarksarray[] = $summarks[$step->questionusageid];
         }
+        if ($dovariantalso) {
+            $this->initial_steps_walker($step, $stats->variantstats[$step->variant], $summarks, $positionstat, false);
+
+        }
     }
 
     /**
      * Perform some computations on the per-question statistics calculations after
-     * we have been through all the states.
+     * we have been through all the step data.
      *
      * @param calculated $stats question stats to update.
+     * @param bool       $dovariantsalso do we also want to do the same calculations for the variants?
      */
-    protected function initial_question_walker($stats) {
+    protected function initial_question_walker($stats, $dovariantsalso = true) {
         $stats->markaverage = $stats->totalmarks / $stats->s;
 
         if ($stats->maxmark != 0) {
@@ -376,6 +450,12 @@ class calculator {
 
         sort($stats->markarray, SORT_NUMERIC);
         sort($stats->othermarksarray, SORT_NUMERIC);
+
+        if ($dovariantsalso) {
+            foreach ($stats->variantstats as $variantstat) {
+                $this->initial_question_walker($variantstat, false);
+            }
+        }
     }
 
     /**
@@ -385,8 +465,9 @@ class calculator {
      * @param object $step        the state to add to the statistics.
      * @param calculated $stats       the question statistics we are accumulating.
      * @param array  $summarks    of the sum of marks for each question usage, indexed by question usage id
+     * @param bool   $dovariantalso do we also want to do the same calculations for the variant?
      */
-    protected function secondary_steps_walker($step, $stats, $summarks) {
+    protected function secondary_steps_walker($step, $stats, $summarks, $dovariantalso = true) {
         $markdifference = $step->mark - $stats->markaverage;
         if ($stats->subquestion) {
             $othermarkdifference = $summarks[$step->questionusageid] - $stats->othermarkaverage;
@@ -403,14 +484,19 @@ class calculator {
         $stats->covariancesum += $markdifference * $othermarkdifference;
         $stats->covariancemaxsum += $sortedmarkdifference * $sortedothermarkdifference;
         $stats->covariancewithoverallmarksum += $markdifference * $overallmarkdifference;
+
+        if ($dovariantalso) {
+            $this->secondary_steps_walker($step, $stats->variantstats[$step->variant], $summarks, false);
+        }
     }
 
     /**
      * Perform more per-question statistics calculations.
      *
      * @param calculated $stats question stats to update.
+     * @param bool       $dovariantsalso do we also want to do the same calculations for the variants?
      */
-    protected function secondary_question_walker($stats) {
+    protected function secondary_question_walker($stats, $dovariantsalso = true) {
 
         if ($stats->s > 1) {
             $stats->markvariance = $stats->markvariancesum / ($stats->s - 1);
@@ -449,6 +535,13 @@ class calculator {
         } else {
             $stats->discriminativeefficiency = null;
         }
+
+
+        if ($dovariantsalso) {
+            foreach ($stats->variantstats as $variantstat) {
+                $this->secondary_question_walker($variantstat, false);
+            }
+        }
     }
 
     /**
@@ -464,9 +557,9 @@ class calculator {
      * @param $qubaids \qubaid_condition
      */
     protected function cache_stats($qubaids) {
-        foreach ($this->questionstats as $questionstat) {
+         foreach ($this->questionstats as $questionstat) {
             $questionstat->cache($qubaids);
-        }
+         }
 
         foreach ($this->subquestionstats as $subquestionstat) {
             $subquestionstat->cache($qubaids);
index 71015a7..241b975 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2014012300.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2014012300.01;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.