From d79fef2ab51b520879ce11b2dc48853bd47c1359 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Tue, 28 Aug 2018 18:15:20 +1000 Subject: [PATCH] MDL-63186 question: Calculate extremums of summarised questions Modified calculated_random_question_summary class so that it can return minimum and maximum of each attribute of the sub questions it is summarising. Part of MDL-62610 --- .../all_calculated_for_qubaid_condition.php | 18 +++-- .../calculated_random_question_summary.php | 75 +++++++++++++++++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/question/classes/statistics/questions/all_calculated_for_qubaid_condition.php b/question/classes/statistics/questions/all_calculated_for_qubaid_condition.php index 8e538e66fb0..d3b384a2404 100644 --- a/question/classes/statistics/questions/all_calculated_for_qubaid_condition.php +++ b/question/classes/statistics/questions/all_calculated_for_qubaid_condition.php @@ -405,7 +405,7 @@ class all_calculated_for_qubaid_condition { * * @param int $slot the slot no * @param bool $limited limit number of variants and sub-questions displayed? - * @return calculated|calculated_for_subquestion[] stats to display + * @return calculated|calculated_for_subquestion|calculated_random_question_summary[] stats to display */ protected function all_subq_and_variant_stats_for_slot($slot, $limited) { // Random question in this slot? @@ -414,10 +414,6 @@ class all_calculated_for_qubaid_condition { if ($limited) { $randomquestioncalculated = $this->for_slot($slot); - // If we're showing a limited view of the statistics then add a - // random question summary stat rather than a stat for each - // subquestion. - $toreturn[] = $this->make_new_random_question_summary_stat($randomquestioncalculated); if ($subqvariantstats = $this->all_subq_variants_for_one_slot($slot)) { $subqvariantfacilitystats = $this->find_min_median_and_max_facility_stats_objects($subqvariantstats); @@ -429,6 +425,12 @@ class all_calculated_for_qubaid_condition { $toreturn = array_merge($toreturn, $subqfacilitystats); } + // If we're showing a limited view of the statistics then add a + // random question summary stat rather than a stat for each + // subquestion. + $summarystat = $this->make_new_random_question_summary_stat($randomquestioncalculated, $subqstats); + $toreturn = array_merge([$summarystat], $toreturn); + foreach ($toreturn as $index => $calculated) { $calculated->subqdisplayorder = $index; } @@ -479,13 +481,13 @@ class all_calculated_for_qubaid_condition { * subquestion directly. * * @param calculated $randomquestioncalculated The calculated instance for the random question slot. + * @param calculated[] $subquestionstats The instances of the calculated stats of the questions that are being summarised. * @return calculated_random_question_summary */ - protected function make_new_random_question_summary_stat($randomquestioncalculated) { + protected function make_new_random_question_summary_stat($randomquestioncalculated, $subquestionstats) { $question = $randomquestioncalculated->question; $slot = $randomquestioncalculated->slot; - $calculatedsummary = new calculated_random_question_summary($question, $slot); - $calculatedsummary->subquestions = $randomquestioncalculated->subquestions; + $calculatedsummary = new calculated_random_question_summary($question, $slot, $subquestionstats); return $calculatedsummary; } diff --git a/question/classes/statistics/questions/calculated_random_question_summary.php b/question/classes/statistics/questions/calculated_random_question_summary.php index 91d62c1e581..2075421cf74 100644 --- a/question/classes/statistics/questions/calculated_random_question_summary.php +++ b/question/classes/statistics/questions/calculated_random_question_summary.php @@ -44,6 +44,25 @@ class calculated_random_question_summary extends calculated { */ public $subqdisplayorder; + /** + * @var calculated[] The instances storing the calculated stats of the questions that are being summarised. + */ + protected $subqstats; + + /** + * calculated_random_question_summary constructor. + * + * @param \stdClass $question + * @param int $slot + * @param calculated[] $subqstats The instances of the calculated stats of the questions that are being summarised. + */ + public function __construct($question, $slot, $subqstats) { + parent::__construct($question, $slot); + + $this->subqstats = $subqstats; + $this->subquestions = implode(',', array_column($subqstats, 'questionid')); + } + /** * This is a summary stat so never breakdown by variant. * @@ -52,4 +71,60 @@ class calculated_random_question_summary extends calculated { public function break_down_by_variant() { return false; } + + /** + * Returns the minimum and maximum values of the given attribute in the summarised calculated stats. + * + * @param string $attribute The attribute that we are looking for its extremums. + * @return array An array of [min,max] + */ + public function get_min_max_of($attribute) { + $getmethod = 'get_min_max_of_' . $attribute; + if (method_exists($this, $getmethod)) { + return $this->$getmethod(); + } else { + $min = $max = null; + + // We cannot simply use min or max functions because, in theory, some attributes might be non-scalar. + foreach (array_column($this->subqstats, $attribute) as $value) { + if (is_scalar($value)) { + if (!isset($min)) { + $min = $value; + } + if (!isset($max)) { + $max = $value; + } + + $min = min($min, $value); + $max = max($max, $value); + } + } + + return [$min, $max]; + } + } + + /** + * Returns the minimum and maximum values of the standard deviation in the summarised calculated stats. + * @return array An array of [min,max] + */ + protected function get_min_max_of_sd() { + $min = $max = null; + + foreach ($this->subqstats as $subqstat) { + if (isset($subqstat->sd) && $subqstat->maxmark) { + if (!isset($min)) { + $min = $subqstat->sd / $subqstat->maxmark; + } + if (!isset($max)) { + $max = $subqstat->sd / $subqstat->maxmark; + } + + $min = min($min, $subqstat->sd / $subqstat->maxmark); + $max = max($max, $subqstat->sd / $subqstat->maxmark); + } + } + + return [$min, $max]; + } }