MDL-47009 Grades: Improve natural weighting algorithm
authorDamyon Wiese <damyon@moodle.com>
Thu, 18 Sep 2014 06:43:34 +0000 (14:43 +0800)
committerAdrian Greeve <adrian@moodle.com>
Fri, 3 Oct 2014 05:53:01 +0000 (13:53 +0800)
It's still not perfect, but this is getting closer.

This is based on Johns work on MDL-47009 (just the algorithm). There are some additional
changes to scale the weights if they do not add up to 1.

Part of: MDL-46576

lib/grade/grade_category.php

index 0de0b85..6ce3dbe 100644 (file)
@@ -926,13 +926,35 @@ class grade_category extends grade_object {
             case GRADE_AGGREGATE_SUM:    // Add up all the items.
                 $num = count($grade_values);
                 $sum = 0;
-                foreach ($grade_values as $itemid => $grade_value) {
-                    $sum += $grade_value * $items[$itemid]->aggregationcoef2;
-                    if ($weights !== null && $num > 0) {
-                        $weights[$itemid] = $items[$itemid]->aggregationcoef2;
+                $sumweights = 0;
+                $weightsfix = 1;
+                $grademin = 0;
+                $grademax = 0;
+                foreach ($grade_values as $itemid => $gradevalue) {
+                    $gradeitemrange = $items[$itemid]->grademax - $items[$itemid]->grademin;
+
+                    // Extra credit.
+                    if (!empty($items[$itemid]->aggregationcoef)) {
+                        $grademax += $gradeitemrange;
+                        $sumweights += $items[$itemid]->aggregationcoef2;
                     }
                 }
-                $agg_grade = $sum;
+                if ($sumweights != 1 && $sumweights != 0) {
+                    $weightsfix = 1 / $sumweights;
+                }
+                foreach ($grade_values as $itemid => $gradevalue) {
+                    $sum += $gradevalue * $items[$itemid]->aggregationcoef2 * $grademax * $weightsfix;
+                    if ($weights !== null) {
+                        $weights[$itemid] = $items[$itemid]->aggregationcoef2 * $weightsfix;
+                    }
+                }
+                if ($grademax > 0) {
+                    $agg_grade = $sum / $grademax; // Re-normalize score.
+                } else {
+                    // Every item in the category is extra credit.
+                    $agg_grade = $sum;
+                    $grademax = $sum;
+                }
 
                 break;