From c5887eb432e6c83c13ab4bbd07e4436696d67203 Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 19 Dec 2007 19:52:11 +0000 Subject: [PATCH] - A working tour annealer.. Now I just have to glue it all together. --- admin/tours_sa.php | 237 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 admin/tours_sa.php diff --git a/admin/tours_sa.php b/admin/tours_sa.php new file mode 100644 index 0000000..994ebe7 --- /dev/null +++ b/admin/tours_sa.php @@ -0,0 +1,237 @@ + + Copyright (C) 2005 James Grant + Copyright (C) 2008 Daivd Grant + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +?> +"); + + +function set_status($txt) +{ + TRACE("Status: $txt\n"); + return; + mysql_query("UPDATE config SET val='$txt' WHERE + var='tours_scheduler_activity' AND year=0"); +} + +$set_percent_last_percent = -1; +function set_percent($n) +{ + global $set_percent_last_percent; + $p = floor($n); + if($p == $set_percent_last_percent) return; + TRACE("Progress: $p\%\n"); + $set_percent_last_percent = $p; + return; + mysql_query("UPDATE config SET val='$p' WHERE + var='tours_scheduler_percent' AND year=0"); +} + +set_status("Initializing..."); +set_percent(0); + +/* The cost function is: + - Foreach student in a tour + +15 - Above the grade level + +25 - Below the grade level + + +*/ + +/* Compute the cost of adding a judge to a team */ + +function tour_cost_function($annealer, $bucket_id, $ids) +{ + global $config; + global $tid; + global $tours; + global $students; + /* Bucket ID is the tour number */ + /* ids are the judge ids currently in the bucket */ + +// TRACE("Bucket id=$bucket_id, ids="); +// TRACE_R($ids); + + $cost = 0; + + $t =& $tours[$bucket_id]; + $tid = $t['id']; + + /* Compute the over max / under min costs */ + $c = count($ids); + $over = ($c > $t['capacity']) ? $c - $t['capacity'] : 0; + $under = ($c < ($t['capacity']/4)) ? ($t['capacity']/4) - $c : 0; + $cost += $over * 100; + $cost += $under * 200; + +// TRACE("Under min=$min, over max=$max\n"); + + $schools = array(); + /* For each student on the tour */ + foreach($ids as $x=>$sid) { + $s =& $students[$sid]; + + /* Score the rank */ + $rank_cost = -1; + foreach($s['rank'] as $rank=>$rank_tid) { + if($rank_tid != $tid) continue; + $rank_cost = ($rank * $rank * 5) - 5; + } + if($rank_cost == -1) { + $rank_cost = $config['tours_choices_max'] * $config['tours_choices_max'] * 5; + } + $cost += $rank_cost; + + /* Check for student below/above grade range */ + if($s['grade'] < $t['grade_min']) $cost += 15; + if($s['grade'] > $t['grade_min']) $cost += 25; + + /* Record the school */ + $schools[$s['schools_id']]++; + } + + /* Search the schools array for insteances of '1' */ + foreach($schools as $sid=>$cnt) { + if($cnt == 1) $cost += 5; + } + +// TRACE("Team $bucket_id, cost is $cost\n"); + + return $cost; +} + +set_status("Cleaning existing tour assignments..."); +TRACE("\n\n"); +$q=mysql_query("DELETE FROM tours_choice + WHERE year='{$config['FAIRYEAR']}' + AND rank='0'"); + +set_status("Loading Data From Database..."); +TRACE("\n\n"); +TRACE("Tours...\n"); +$tours = array(); +$q=mysql_query("SELECT * FROM tours WHERE year='{$config['FAIRYEAR']}'"); +$x=0; +while($r=mysql_fetch_object($q)) { + $tours[$x]['capacity'] = $r->capacity; + $tours[$x]['grade_min'] = $r->grade_min; + $tours[$x]['grade_max'] = $r->grade_max; + $tours[$x]['id'] = $r->id; + $tours[$x]['name'] = $r->name; + TRACE(" $x: #{$r->id} {$r->name} (c:{$r->capacity} g:{$r->grade_min}-{$r->grade_max})\n"); + $x++; +} + +$students = array(); +TRACE("Loading Students...\n"); +$q=mysql_query("SELECT students.id,students.grade, + students.registrations_id, + students.schools_id, + students.firstname, students.lastname, + tours_choice.rank,tours_choice.tour_id + FROM students + LEFT JOIN tours_choice ON (tours_choice.students_id=students.id) + LEFT JOIN registrations ON (registrations.id=students.registrations_id) + WHERE + students.year='{$config['FAIRYEAR']}' + AND tours_choice.year='{$config['FAIRYEAR']}' + AND registrations.status='complete' + ORDER BY + students.id, tours_choice.rank + "); +$last_sid = -1; +TRACE(mysql_error()); +while($r=mysql_fetch_object($q)) { + $sid = $r->id; + if($last_sid != $sid) { + $students[$sid]['name'] = $r->firstname.' '.$r->lastname; + $students[$sid]['grade'] = $r->grade; + $students[$sid]['registrations_id'] = $r->registrations_id; + $students[$sid]['rank'] = array(); + $students[$sid]['schools_id'] = $r->schools_id; + $last_sid = $sid; + } + $students[$sid]['rank'][$r->rank] = $r->tour_id; +} +$student_ids = array_keys($students); +TRACE(" ".(count($student_ids))." students loaded\n"); + +function tours_assignment_update($progress, $total) +{ + set_percent(($progress * 50) / $total); +} + +TRACE("Effort: {$config['effort']}\n"); +set_status("Assigning students to tours"); +$e = 100 + 10 * ($config['effort'] / 100); +$a = new annealer(count($tours), 50, $e, 0.98, + tour_cost_function, $student_ids); +$a->set_update_callback(tours_assignment_update); +$a->anneal(); + +/* Record the assignments */ +foreach($tours as $x=>$t) { + TRACE("#{$t['id']} {$t['name']} (c:{$t['capacity']} g:{$t['grade_min']}-{$t['grade_max']})\n"); + + $sids = $a->bucket[$x]; + + TRACE(" - Cost:{$a->bucket_cost[$x]} Students: ".(count($sids))."\n"); + foreach($sids as $sid) { + $s = $students[$sid]; + $tids = implode(' ', $s['rank']); + TRACE(" - {$s['name']} ($tids) (g:{$s['grade']} s:{$s['schools_id']})\n"); + mysql_query("INSERT INTO tours_choice + (`students_id`,`registrations_id`, + `tour_id`,`year`,`rank`) + VALUES ( + '$sid', '{$s['registrations_id']}', + '{$t['id']}', '{$config['FAIRYEAR']}', + '0')"); + } +} + +TRACE("All Done.\n"); +echo ""; + +set_percent(-1); +set_status("Done"); + +//echo happy("Scheduler completed successfully"); + +//send_footer(); +?>