Skip to content

Commit

Permalink
fix edmonds-karp distribution algorithm for teamvote
Browse files Browse the repository at this point in the history
  • Loading branch information
irinahpe committed Aug 21, 2024
1 parent 94b2878 commit ba2786a
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 28 deletions.
10 changes: 6 additions & 4 deletions locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1925,12 +1925,14 @@ public function save_ratings_to_db($userid, array $data) {
$rating->groupid = $votegroupid;
$DB->insert_record('ratingallocate_ratings', $rating);

// If teamvote is enabled, create ratings for all groupmembers.
// If teamvote is enabled, create ratings for all other groupmembers.
if ($teamvote && $votegroup) {
$teammembers = groups_get_members($votegroupid, 'u.id');
foreach ($teammembers as $member) {
$rating->userid = $member->id;
$DB->insert_record('ratingallocate_ratings', $rating);
if ($member->id != $userid) {
$rating->userid = $member->id;
$DB->insert_record('ratingallocate_ratings', $rating);
}
}
}

Expand Down Expand Up @@ -2431,7 +2433,7 @@ public function get_coarser_groups_for_grouping($groupingid) {
$completelycontained = true;
foreach ($innergroupmembers as $groupmember) {
// Check if innergroup is not at all conatained in outergroup.
if (groups_is_member($outergroup, $groupmember->id)) {
if (groups_is_member($outergroup->id, $groupmember->id)) {
$notcontained = false;
} else {
// Now check if innergroup is completely contained in outergroup
Expand Down
2 changes: 1 addition & 1 deletion mod_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public function validation($data, $files) {
$usersingrouping = groups_get_grouping_members($data['teamvotegroupingid'], 'u.id');
$userinmultipleteams = false;
foreach ($usersingrouping as $user) {
if (count(groups_get_user_groups($COURSE->id, $user)[$data['teamvotegroupingid']]) > 1) {
if (count(groups_get_user_groups($COURSE->id, $user->id)[$data['teamvotegroupingid']]) > 1) {
$userinmultipleteams = true;
break;
}
Expand Down
34 changes: 19 additions & 15 deletions solver/edmonds-karp.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function compute_distribution($choicerecords, $ratings, $usercount, $team
$sink = $choicecount + $usercount + 1;

list($fromuserid, $touserid, $fromchoiceid, $tochoiceid) = $this->setup_id_conversions($usercount, $ratings);

$this->setup_graph($choicecount, $usercount, $fromuserid, $fromchoiceid, $ratings, $choicedata, $source, $sink, -1);

// Now that the datastructure is complete, we can start the algorithm
Expand All @@ -59,7 +59,7 @@ public function compute_distribution($choicerecords, $ratings, $usercount, $team
// http://stackoverflow.com/questions/6681075/while-loop-in-php-with-assignment-operator
// Look for an augmenting path (a shortest path from the source to the sink).
while ($path = $this->find_shortest_path_bellf($source, $sink)) { // If the function returns null, the while will stop.
// Reverse the augmentin path, thereby distributing a user into a group.
// Reverse the augmenting path, thereby distributing a user into a group.
$this->augment_flow($path);
unset($path); // Clear up old path.
}
Expand All @@ -73,7 +73,7 @@ public function compute_distribution($choicerecords, $ratings, $usercount, $team

list($fromteamid, $toteamid, $fromchoiceid, $tochoiceid) = $this->setup_id_conversions_for_teamvote($teamcount, $ratings);

$this->setup_graph_for_teamvote($choicecount, $teamcount, $fromteamid, $fromchoiceid, $ratings, $choicedata, $source, $sink, -1);
$this->setup_graph_for_teamvote($choicecount, $teamcount, $fromteamid, $fromchoiceid, $ratings, $choicedata, $source, $sink, $teamvote, -1);

// Now that the datastructure is complete, we can start the algorithm
// This is an adaptation of the Ford-Fulkerson algorithm
Expand All @@ -82,7 +82,7 @@ public function compute_distribution($choicerecords, $ratings, $usercount, $team
// Look for an augmenting path (a shortest path from the source to the sink).
while ($path = $this->find_shortest_path_bellf_cspf2($source, $sink, $teamvote, $toteamid)) { // If the function returns null, the while will stop.
// Reverse the augmentin path, thereby distributing a user into a group.
$this->augment_flow($path);
$this->augment_flow($path, $teamvote, $toteamid);
unset($path); // Clear up old path.
}
return $this->extract_allocation($toteamid, $tochoiceid);
Expand All @@ -105,10 +105,8 @@ private function find_shortest_path_bellf_cspf2 ($from, $to, $teamvote, $toteami

// Stop if no shortest path is found.
$i=1;
while ($pathcandidate = $this->find_shortest_path_bellf($from, $to)) {
// var_dump($this->graph);
var_dump($i);
var_dump($pathcandidate);
while (($pathcandidate = $this->find_shortest_path_bellf($from, $to)) && $i<10) {

$foundedge = null;

foreach ($this->graph[$pathcandidate[1]] as $index => $edge) {
Expand All @@ -118,21 +116,27 @@ private function find_shortest_path_bellf_cspf2 ($from, $to, $teamvote, $toteami
break;
}
}
if ($foundedge->space > $teamvote[$toteamid[$pathcandidate[2]]]) {

if ($foundedge->space >= $teamvote[$toteamid[$pathcandidate[2]]]) {
// We just found the shortest path fulfilling the constraint.
return $pathcandidate;

} else {

$foundedgetoremove = null;
foreach ($this->graph[$pathcandidate[2]] as $index => $edge) {
if ($edge->to == $pathcandidate[1]) {
$foundedgetoremove = $edge;
$foundedgeidtoremove = $index;
}
}

// Remove the edge since this path is impossible.
array_splice($this->graph[1], $foundedgeid, 1);
// Add a new edge in the opposite direction whose weight has an opposite sign
// array_push($this->graph[$to], new edge($to, $from, -1 * $edge->weight));
// according to php doc, this is faster.
// $this->graph[2][] = new edge(2, 1, -1 * $edge->weight);
array_splice($this->graph[$pathcandidate[2]], $foundedgeidtoremove, 1);
}
unset($pathcandidate);
$i++;
}
var_dump("nix gefunden");
return null;

}
Expand Down
2 changes: 1 addition & 1 deletion solver/ford-fulkerson-koegel.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public function compute_distribution($choicerecords, $ratings, $usercount, $team
$sink = $groupcount + $teamcount + 1;
list($fromteamid, $toteamid, $fromgroupid, $togroupid) = $this->setup_id_conversions_for_teamvote($usercount, $ratings);

$this->setup_graph_for_teamvote($groupcount, $teamcount, $fromteamid, $fromgroupid, $ratings, $groupdata, $source, $sink);
$this->setup_graph_for_teamvote($groupcount, $teamcount, $fromteamid, $fromgroupid, $ratings, $groupdata, $source, $sink, $teamvote);

// Now that the datastructure is complete, we can start the algorithm
// This is an adaptation of the Ford-Fulkerson algorithm
Expand Down
25 changes: 18 additions & 7 deletions solver/solver-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,15 @@ public function distribute_users(\ratingallocate $ratingallocate) {
$userdistributions = $distributions;
} else {
// Map choiceids to every user of the team it is mapped to.
$userids = array();

foreach ($distributions as $choiceid => $teamids) {
$userids = array();
foreach ($teamids as $teamid) {
array_merge($userids, groups_get_members($teamid, 'u.id'));
$userids = array_merge($userids,
array_map(function($user) {
return $user->id;
}, groups_get_members($teamid, 'u.id'))
);
}
$userdistributions[$choiceid] = $userids;
}
Expand All @@ -143,7 +148,7 @@ public function distribute_users(\ratingallocate $ratingallocate) {
*
* @param $touserid a map mapping from indexes in the graph to userids (or teamids)
* @param $tochoiceid a map mapping from indexes in the graph to choiceids
* @return an array of the form array(groupid => array(userid, ...), ...)
* @return array of the form array(groupid => array(userid, ...), ...)
*/
protected function extract_allocation($touserid, $tochoiceid) {
$distribution = array();
Expand All @@ -157,6 +162,7 @@ protected function extract_allocation($touserid, $tochoiceid) {
}
}
}

return $distribution;
}

Expand Down Expand Up @@ -293,9 +299,10 @@ protected function setup_graph($choicecount, $usercount, $fromuserid, $fromchoic
* @param type $choicedata
* @param type $source
* @param type $sink
* @param type $teamvote
*/
protected function setup_graph_for_teamvote($choicecount, $teamcount, $fromteamid, $fromchoiceid, $ratings, $choicedata, $source, $sink,
$weightmult = 1) {
$teamvote, $weightmult = 1) {
// Construct the datastructures for the algorithm
// A directed weighted bipartite graph.
// A source is connected to all users with unit cost.
Expand Down Expand Up @@ -324,8 +331,9 @@ protected function setup_graph_for_teamvote($choicecount, $teamcount, $fromteami
$team = $fromteamid[$rating->groupid];
$choice = $fromchoiceid[$rating->choiceid];
$weight = $rating->rating;
$membercount = $teamvote[$rating->groupid];
if ($weight > 0) {
$this->graph[$team][] = new edge($team, $choice, $weightmult * $weight);
$this->graph[$team][] = new edge($team, $choice, $weightmult * $weight * $membercount);
}
}

Expand Down Expand Up @@ -357,18 +365,21 @@ protected function augment_flow($path, $teamvote=false, $toteamid=null) {
break;
}
}
// The second to last node in a path has to be a choice-node.

// The node before that has to be a teamnode (or usernode), distribute them to this choice.
if (!$teamvote) {
// If teamvote=false, reduce its space by one, because one user just got distributed into it.
$space = 1;
} else {
// If teamvote is enabled, reduce its space by amount of groupmembers.
$space = $teamvote[$toteamid[$path[$i + 1]]];
$space = $teamvote[$toteamid[$path[2]]];
}

// The second to last node in a path has to be a choice-node.
if ($i == 1 && $edge->space > $space) {

$edge->space = $edge->space - $space;

} else {
// Remove the edge.
array_splice($this->graph[$from], $foundedgeid, 1);
Expand Down

0 comments on commit ba2786a

Please sign in to comment.