001package org.cpsolver.instructor.test; 002 003import java.io.BufferedReader; 004import java.io.File; 005import java.io.FileReader; 006import java.io.IOException; 007import java.io.PrintWriter; 008import java.text.DecimalFormat; 009import java.util.ArrayList; 010import java.util.Collections; 011import java.util.Comparator; 012import java.util.HashMap; 013import java.util.HashSet; 014import java.util.List; 015import java.util.Map; 016import java.util.Set; 017import java.util.TreeSet; 018 019import org.apache.log4j.Logger; 020import org.cpsolver.coursett.Constants; 021import org.cpsolver.coursett.model.TimeLocation; 022import org.cpsolver.ifs.assignment.Assignment; 023import org.cpsolver.ifs.model.Constraint; 024import org.cpsolver.ifs.util.DataProperties; 025import org.cpsolver.ifs.util.ToolBox; 026import org.cpsolver.instructor.Test; 027import org.cpsolver.instructor.constraints.SameInstructorConstraint; 028import org.cpsolver.instructor.constraints.SameLinkConstraint; 029import org.cpsolver.instructor.criteria.DifferentLecture; 030import org.cpsolver.instructor.model.Course; 031import org.cpsolver.instructor.model.Instructor; 032import org.cpsolver.instructor.model.Attribute; 033import org.cpsolver.instructor.model.Preference; 034import org.cpsolver.instructor.model.Section; 035import org.cpsolver.instructor.model.TeachingAssignment; 036import org.cpsolver.instructor.model.TeachingRequest; 037 038/** 039 * Math teaching assistant assignment problem. Different file format for the input data. 040 * 041 * @version IFS 1.3 (Instructor Sectioning)<br> 042 * Copyright (C) 2016 Tomáš Müller<br> 043 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 044 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 045 * <br> 046 * This library is free software; you can redistribute it and/or modify 047 * it under the terms of the GNU Lesser General Public License as 048 * published by the Free Software Foundation; either version 3 of the 049 * License, or (at your option) any later version. <br> 050 * <br> 051 * This library is distributed in the hope that it will be useful, but 052 * WITHOUT ANY WARRANTY; without even the implied warranty of 053 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 054 * Lesser General Public License for more details. <br> 055 * <br> 056 * You should have received a copy of the GNU Lesser General Public 057 * License along with this library; if not see 058 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 059 */ 060public class MathTest extends Test { 061 private static Logger sLog = Logger.getLogger(MathTest.class); 062 063 public MathTest(DataProperties properties) { 064 super(properties); 065 removeCriterion(DifferentLecture.class); 066 } 067 068 public String getLevel(Instructor instructor) { 069 for (Attribute attribute: instructor.getAttributes()) 070 if (attribute.getType().getTypeName().equals("Level")) return attribute.getAttributeName(); 071 return null; 072 } 073 074 public String toString(Instructor instructor) { 075 StringBuffer sb = new StringBuffer(); 076 sb.append(instructor.getExternalId()); 077 sb.append(",\"" + instructor.getAvailable() + "\""); 078 Collections.sort(instructor.getCoursePreferences(), new Comparator<Preference<Course>>() { 079 @Override 080 public int compare(Preference<Course> p1, Preference<Course> p2) { 081 if (p1.getPreference() == p2.getPreference()) 082 return p1.getTarget().getCourseName().compareTo(p2.getTarget().getCourseName()); 083 return p1.getPreference() < p2.getPreference() ? -1 : 1; 084 } 085 }); 086 for (int i = 0; i < 3; i++) { 087 Preference<Course> p = (i < instructor.getCoursePreferences().size() ? instructor.getCoursePreferences().get(i) : null); 088 sb.append("," + (p == null ? "" : p.getTarget().getCourseName())); 089 } 090 sb.append("," + (instructor.getPreference() == 0 ? "Yes" : "No")); 091 sb.append("," + (instructor.isBackToBackPreferred() ? "1" : instructor.isBackToBackDiscouraged() ? "-1" : "0")); 092 sb.append("," + new DecimalFormat("0.0").format(instructor.getMaxLoad())); 093 String level = getLevel(instructor); 094 sb.append("," + (level == null ? "" : level)); 095 return sb.toString(); 096 } 097 098 public String getLink(TeachingRequest.Variable request) { 099 for (Constraint<TeachingRequest.Variable, TeachingAssignment> c: request.constraints()) { 100 if (c instanceof SameLinkConstraint) 101 return c.getName().substring(c.getName().indexOf('-') + 1); 102 } 103 return null; 104 } 105 106 public Long getAssignmentId(TeachingRequest.Variable request) { 107 for (Constraint<TeachingRequest.Variable, TeachingAssignment> c: request.constraints()) { 108 if (c instanceof SameInstructorConstraint && ((SameInstructorConstraint) c).getConstraintId() != null) 109 return ((SameInstructorConstraint) c).getConstraintId(); 110 } 111 return null; 112 } 113 114 public int countDiffLinks(Set<TeachingAssignment> assignments) { 115 Set<String> links = new HashSet<String>(); 116 for (TeachingAssignment assignment : assignments) { 117 String link = getLink(assignment.variable()); 118 if (link != null) 119 links.add(link); 120 } 121 return Math.max(0, links.size() - 1); 122 } 123 124 public String toString(TeachingRequest.Variable request) { 125 StringBuffer sb = new StringBuffer(); 126 Long assId = getAssignmentId(request); 127 sb.append(assId == null ? "" : assId); 128 sb.append("," + request.getCourse().getCourseName()); 129 Section section = request.getSections().get(0); 130 sb.append("," + section.getSectionName()); 131 sb.append("," + section.getTimeName(true)); 132 sb.append(",\"" + (section.hasRoom() ? section.getRoom() : "") + "\""); 133 String link = getLink(request); 134 sb.append("," + (link == null ? "" : link)); 135 Map<String, Integer> levels = new HashMap<String, Integer>(); 136 for (Preference<Attribute> p: request.getRequest().getAttributePreferences()) 137 levels.put(p.getTarget().getAttributeName(), - p.getPreference()); 138 sb.append(",\"" + levels + "\""); 139 sb.append("," + new DecimalFormat("0.0").format(request.getRequest().getLoad())); 140 return sb.toString(); 141 } 142 143 @Override 144 protected boolean load(File dir, Assignment<TeachingRequest.Variable, TeachingAssignment> assignment) { 145 if (!dir.isDirectory()) 146 return super.load(dir, assignment); 147 try { 148 String line = null; 149 BufferedReader r = new BufferedReader(new FileReader(new File(dir, "courses.csv"))); 150 Map<String, Course> courses = new HashMap<String, Course>(); 151 Map<Long, List<TeachingRequest>> id2classes = new HashMap<Long, List<TeachingRequest>>(); 152 Map<String, List<TeachingRequest>> link2classes = new HashMap<String, List<TeachingRequest>>(); 153 long assId = 0, reqId = 0; 154 while ((line = r.readLine()) != null) { 155 if (line.trim().isEmpty()) 156 continue; 157 String[] fields = line.split(","); 158 Long id = Long.valueOf(fields[0]); 159 String course = fields[1]; 160 String section = fields[2]; 161 int idx = 3; 162 int dayCode = 0; 163 idx: while (idx < fields.length && (idx == 3 || fields[idx].length() == 1)) { 164 for (int i = 0; i < fields[idx].length(); i++) { 165 switch (fields[idx].charAt(i)) { 166 case 'M': 167 dayCode += Constants.DAY_CODES[0]; 168 break; 169 case 'T': 170 dayCode += Constants.DAY_CODES[1]; 171 break; 172 case 'W': 173 dayCode += Constants.DAY_CODES[2]; 174 break; 175 case 'R': 176 dayCode += Constants.DAY_CODES[3]; 177 break; 178 case 'F': 179 dayCode += Constants.DAY_CODES[4]; 180 break; 181 default: 182 break idx; 183 } 184 } 185 idx++; 186 } 187 int startSlot = 0; 188 if (dayCode > 0) { 189 int time = Integer.parseInt(fields[idx++]); 190 startSlot = 12 * (time / 100) + (time % 100) / 5; 191 } 192 String room = null; 193 if (idx < fields.length) 194 room = fields[idx++]; 195 String link = null; 196 if (idx < fields.length) 197 link = fields[idx++]; 198 int length = 12; 199 if (idx < fields.length) { 200 int time = Integer.parseInt(fields[idx++]); 201 int endSlot = 12 * (time / 100) + (time % 100) / 5; 202 length = endSlot - startSlot; 203 if (length == 10) 204 length = 12; 205 else if (length == 15) 206 length = 18; 207 } 208 List<Section> sections = new ArrayList<Section>(); 209 TimeLocation time = new TimeLocation(dayCode, startSlot, length, 0, 0.0, 0, null, "", null, (length == 18 ? 15 : 10)); 210 sections.add(new Section(assId++, id.toString(), section, course + " " + section + " " + time.getName(true) + (room == null ? "" : " " + room), time, room, false, false)); 211 Course c = courses.get(course); 212 if (c == null) { 213 c = new Course(courses.size(), course); 214 courses.put(course, c); 215 } 216 TeachingRequest clazz = new TeachingRequest(reqId++, 1, c, 0f, sections, Constants.sPreferenceLevelRequired, Constants.sPreferenceLevelNeutral); 217 addRequest(clazz); 218 List<TeachingRequest> classes = id2classes.get(id); 219 if (classes == null) { 220 classes = new ArrayList<TeachingRequest>(); 221 id2classes.put(id, classes); 222 } 223 classes.add(clazz); 224 if (link != null && !link.isEmpty()) { 225 List<TeachingRequest> linked = link2classes.get(course + "-" + link); 226 if (linked == null) { 227 linked = new ArrayList<TeachingRequest>(); 228 link2classes.put(course + "-" + link, linked); 229 } 230 linked.add(clazz); 231 } 232 } 233 234 for (Map.Entry<Long, List<TeachingRequest>> e : id2classes.entrySet()) { 235 Long id = e.getKey(); 236 List<TeachingRequest> classes = e.getValue(); 237 if (classes.size() > 1) { 238 SameInstructorConstraint sa = new SameInstructorConstraint(id, "A" + id.toString(), Constants.sPreferenceRequired); 239 for (TeachingRequest c : classes) 240 sa.addVariable(c.getVariables()[0]); 241 addConstraint(sa); 242 } 243 } 244 for (Map.Entry<String, List<TeachingRequest>> e : link2classes.entrySet()) { 245 String link = e.getKey(); 246 List<TeachingRequest> classes = e.getValue(); 247 if (classes.size() > 1) { 248 SameLinkConstraint sa = new SameLinkConstraint(null, link, Constants.sPreferencePreferred); 249 for (TeachingRequest c : classes) 250 sa.addVariable(c.getVariables()[0]); 251 addConstraint(sa); 252 } 253 } 254 255 Attribute.Type level = new Attribute.Type(0l, "Level", false, true); 256 addAttributeType(level); 257 Map<String, Attribute> code2attribute = new HashMap<String, Attribute>(); 258 r.close(); 259 260 r = new BufferedReader(new FileReader(new File(dir, "level_codes.csv"))); 261 String[] codes = r.readLine().split(","); 262 while ((line = r.readLine()) != null) { 263 if (line.trim().isEmpty()) 264 continue; 265 String[] fields = line.split(","); 266 String code = fields[0]; 267 if (code.startsWith("\"") && code.endsWith("\"")) 268 code = code.substring(1, code.length() - 1); 269 Attribute attribute = code2attribute.get(code); 270 if (attribute == null) { 271 attribute = new Attribute(code2attribute.size(), code, level); 272 code2attribute.put(code, attribute); 273 } 274 for (int i = 1; i < codes.length; i++) { 275 int pref = Integer.parseInt(fields[i]); 276 if (pref > 0) 277 for (TeachingRequest clazz : getRequests()) { 278 if (clazz.getCourse().getCourseName().contains(codes[i])) 279 clazz.addAttributePreference(new Preference<Attribute>(attribute, -pref)); 280 } 281 } 282 } 283 r = new BufferedReader(new FileReader(new File(dir, "hours_per_course.csv"))); 284 while ((line = r.readLine()) != null) { 285 if (line.trim().isEmpty()) 286 continue; 287 String[] fields = line.split(","); 288 for (TeachingRequest clazz : getRequests()) { 289 if (clazz.getCourse().getCourseName().contains(fields[0])) 290 clazz.setLoad(Float.parseFloat(fields[1])); 291 } 292 } 293 294 String defaultCode = getProperties().getProperty("TA.DefaultLevelCode", "XXX"); 295 Attribute defaultAttribute = code2attribute.get(defaultCode); 296 if (defaultAttribute == null) { 297 defaultAttribute = new Attribute(code2attribute.size(), defaultCode, level); 298 code2attribute.put(defaultCode, defaultAttribute); 299 } 300 for (TeachingRequest.Variable clazz : variables()) { 301 sLog.info("Added class " + toString(clazz)); 302 if (clazz.getRequest().getAttributePreferences().isEmpty()) { 303 sLog.error("No level: " + toString(clazz)); 304 clazz.getRequest().addAttributePreference(new Preference<Attribute>(defaultAttribute, -1)); 305 } 306 if (clazz.getRequest().getLoad() == 0.0) { 307 sLog.error("No load: " + toString(clazz)); 308 clazz.getRequest().setLoad(getProperties().getPropertyFloat("TA.DefaultLoad", 10f)); 309 } 310 } 311 312 r = new BufferedReader(new FileReader(new File(dir, "students.csv"))); 313 Set<String> studentIds = new HashSet<String>(); 314 double studentMaxLoad = 0.0; 315 while ((line = r.readLine()) != null) { 316 if (line.trim().isEmpty()) 317 continue; 318 String[] fields = line.split(","); 319 if ("puid".equals(fields[0])) 320 continue; 321 int idx = 0; 322 String id = fields[idx++]; 323 if (!studentIds.add(id)) { 324 sLog.error("Student " + id + " is two or more times in the file."); 325 } 326 boolean[] av = new boolean[50]; 327 for (int i = 0; i < 50; i++) 328 av[i] = "1".equals(fields[idx++]); 329 List<String> prefs = new ArrayList<String>(); 330 for (int i = 0; i < 3; i++) { 331 String p = fields[idx++].replace("Large lecture", "LEC").replace("Lecture", "LEC").replace("Recitation", "REC"); 332 if (p.startsWith("MA ")) 333 p = p.substring(3); 334 if ("I have no preference".equals(p)) 335 continue; 336 prefs.add(p); 337 } 338 boolean grad = "Yes".equals(fields[idx++]); 339 int b2b = Integer.parseInt(fields[idx++]); 340 float maxLoad = Float.parseFloat(fields[idx++]); 341 if (maxLoad == 0) 342 maxLoad = getProperties().getPropertyFloat("TA.DefaultMaxLoad", 20f); 343 String code = (idx < fields.length ? fields[idx++] : null); 344 Instructor instructor = new Instructor(Long.valueOf(id.replace("-","")), id, null, grad ? Constants.sPreferenceLevelNeutral : Constants.sPreferenceLevelDiscouraged, maxLoad); 345 for (int i = 0; i < prefs.size(); i++) { 346 String pref = prefs.get(i); 347 if (pref.indexOf(' ') > 0) pref = pref.substring(0, pref.indexOf(' ')); 348 Course c = courses.get(pref); 349 if (c == null) { 350 c = new Course(courses.size(), pref); 351 courses.put(pref, c); 352 } 353 instructor.addCoursePreference(new Preference<Course>(c, i == 0 ? -10 : i == 1 ? -8 : -5)); 354 } 355 if (code != null) { 356 Attribute attribute = code2attribute.get(code); 357 if (attribute == null) { 358 attribute = new Attribute(code2attribute.size(), code, level); 359 code2attribute.put(code, attribute); 360 } 361 instructor.addAttribute(attribute); 362 } 363 if (b2b == 1) 364 instructor.setBackToBackPreference(Constants.sPreferenceLevelPreferred); 365 else if (b2b == -1) 366 instructor.setBackToBackPreference(Constants.sPreferenceLevelDiscouraged); 367 for (int d = 0; d < 5; d++) { 368 int f = -1; 369 for (int t = 0; t < 10; t++) { 370 if (!av[10 * d + t]) { 371 if (f < 0) f = t; 372 } else { 373 if (f >= 0) { 374 instructor.addTimePreference(new Preference<TimeLocation>(new TimeLocation(Constants.DAY_CODES[d], 90 + 12 * f, (t - f) * 12, 0, 0.0, null, "", null, 0), Constants.sPreferenceLevelProhibited)); 375 f = -1; 376 } 377 } 378 } 379 if (f >= 0) { 380 instructor.addTimePreference(new Preference<TimeLocation>(new TimeLocation(Constants.DAY_CODES[d], 90 + 12 * f, (10 - f) * 12, 0, 0.0, null, "", null, 0), Constants.sPreferenceLevelProhibited)); 381 f = -1; 382 } 383 } 384 if (instructor.getMaxLoad() > 0) { 385 addInstructor(instructor); 386 sLog.info("Added student " + toString(instructor)); 387 int nrClasses = 0; 388 for (TeachingRequest.Variable req : variables()) { 389 if (instructor.canTeach(req.getRequest()) && !req.getRequest().getAttributePreference(instructor).isProhibited()) { 390 sLog.info(" -- " + toString(req) + "," + (-req.getRequest().getAttributePreference(instructor).getPreferenceInt()) + "," + (-instructor.getCoursePreference(req.getCourse()).getPreference())); 391 nrClasses++; 392 } 393 } 394 if (nrClasses == 0) { 395 sLog.info(" -- no courses available"); 396 } 397 studentMaxLoad += instructor.getMaxLoad(); 398 } else { 399 sLog.info("Ignoring student " + instructor); 400 if (instructor.getMaxLoad() == 0) 401 sLog.info(" -- zero max load"); 402 else 403 sLog.info(" -- no courses available"); 404 } 405 } 406 r.close(); 407 408 double totalLoad = 0.0; 409 for (TeachingRequest.Variable clazz : variables()) { 410 if (clazz.values(getEmptyAssignment()).isEmpty()) 411 sLog.error("No values: " + toString(clazz)); 412 totalLoad += clazz.getRequest().getLoad(); 413 } 414 415 Map<String, Double> studentLevel2load = new HashMap<String, Double>(); 416 for (Instructor instructor: getInstructors()) { 417 Set<Attribute> levels = instructor.getAttributes(level); 418 String studentLevel = (levels.isEmpty() ? "null" : levels.iterator().next().getAttributeName()); 419 Double load = studentLevel2load.get(studentLevel); 420 studentLevel2load.put(studentLevel, instructor.getMaxLoad() + (load == null ? 0.0 : load)); 421 } 422 sLog.info("Student max loads: (total: " + sDoubleFormat.format(studentMaxLoad) + ")"); 423 for (String studentLevel : new TreeSet<String>(studentLevel2load.keySet())) { 424 Double load = studentLevel2load.get(studentLevel); 425 sLog.info(" " + studentLevel + ": " + sDoubleFormat.format(load)); 426 } 427 Map<String, Double> clazzLevel2load = new HashMap<String, Double>(); 428 for (TeachingRequest.Variable clazz : variables()) { 429 String classLevel = null; 430 TreeSet<String> levels = new TreeSet<String>(); 431 for (Preference<Attribute> ap: clazz.getRequest().getAttributePreferences()) 432 levels.add(ap.getTarget().getAttributeName()); 433 for (String l : levels) { 434 classLevel = (classLevel == null ? "" : classLevel + ",") + l; 435 } 436 if (classLevel == null) 437 classLevel = "null"; 438 if (clazz.getId() < 0) 439 classLevel = clazz.getName(); 440 Double load = clazzLevel2load.get(classLevel); 441 clazzLevel2load.put(classLevel, clazz.getRequest().getLoad() + (load == null ? 0.0 : load)); 442 } 443 sLog.info("Class loads: (total: " + sDoubleFormat.format(totalLoad) + ")"); 444 for (String classLevel : new TreeSet<String>(clazzLevel2load.keySet())) { 445 Double load = clazzLevel2load.get(classLevel); 446 sLog.info(" " + level + ": " + sDoubleFormat.format(load)); 447 } 448 return true; 449 } catch (IOException e) { 450 sLog.error("Failed to load the problem: " + e.getMessage(), e); 451 return false; 452 } 453 } 454 455 @Override 456 protected void generateReports(File dir, Assignment<TeachingRequest.Variable, TeachingAssignment> assignment) throws IOException { 457 PrintWriter out = new PrintWriter(new File(dir, "solution-assignments.csv")); 458 out.println("Assignment Id,Course,Section,Time,Room,Link,Level,Load,Student,Availability,1st Preference,2nd Preference,3rd Preference,Graduate,Back-To-Back,Max Load,Level,Level,Preference"); 459 for (TeachingRequest.Variable request : variables()) { 460 Long assId = getAssignmentId(request); 461 out.print(assId == null ? "" : assId); 462 out.print("," + request.getCourse().getCourseName()); 463 Section section = request.getSections().get(0); 464 out.print("," + section.getSectionType()); 465 out.print("," + section.getTimeName(true)); 466 out.print(",\"" + (section.hasRoom() ? section.getRoom() : "") + "\""); 467 String link = getLink(request); 468 out.print("," + (link == null ? "" : link)); 469 Map<String, Integer> levels = new HashMap<String, Integer>(); 470 for (Preference<Attribute> p: request.getRequest().getAttributePreferences()) 471 if (p.getTarget().getType().getTypeName().equals("Level")) 472 levels.put(p.getTarget().getAttributeName(), - p.getPreference()); 473 out.print(",\"" + levels + "\""); 474 out.print("," + new DecimalFormat("0.0").format(request.getRequest().getLoad())); 475 TeachingAssignment value = assignment.getValue(request); 476 if (value != null) { 477 out.print("," + toString(value.getInstructor())); 478 out.print("," + (-value.getAttributePreference())); 479 out.print("," + (value.getCoursePreference() == -10 ? "1" : value.getCoursePreference() == -8 ? "2" : value.getCoursePreference() == -5 ? "3" : value.getCoursePreference())); 480 } 481 out.println(); 482 } 483 out.flush(); 484 out.close(); 485 486 out = new PrintWriter(new File(dir, "solution-students.csv")); 487 out.println("Student,Availability,1st Preference,2nd Preference,3rd Preference,Graduate,Back-To-Back,Max Load,Level,Assigned Load,Avg Level,Avg Preference,Back-To-Back,Diff Links,1st Assignment,2nd Assignment, 3rd Assignment"); 488 for (Instructor instructor: getInstructors()) { 489 out.print(instructor.getExternalId()); 490 out.print(",\"" + instructor.getAvailable() + "\""); 491 for (int i = 0; i < 3; i++) { 492 Preference<Course> p = (i < instructor.getCoursePreferences().size() ? instructor.getCoursePreferences().get(i) : null); 493 out.print("," + (p == null ? "" : p.getTarget().getCourseName())); 494 } 495 out.print("," + (instructor.getPreference() == 0 ? "Yes" : "No")); 496 out.print("," + (instructor.isBackToBackPreferred() ? "1" : instructor.isBackToBackDiscouraged() ? "-1" : "0")); 497 out.print("," + new DecimalFormat("0.0").format(instructor.getMaxLoad())); 498 String level = getLevel(instructor); 499 out.print("," + (level == null ? "" : level)); 500 Instructor.Context context = instructor.getContext(assignment); 501 out.print("," + new DecimalFormat("0.0").format(context.getLoad())); 502 double att = 0.0, pref = 0.0; 503 for (TeachingAssignment ta : context.getAssignments()) { 504 att += Math.abs(ta.getAttributePreference()); 505 pref += (ta.getCoursePreference() == -10 ? 1 : ta.getCoursePreference() == -8 ? 2 : ta.getCoursePreference() == -5 ? 3 : ta.getCoursePreference()); 506 } 507 int diffLinks = countDiffLinks(context.getAssignments()); 508 out.print("," + (context.getAssignments().isEmpty() ? "" : new DecimalFormat("0.0").format(att / context.getAssignments().size()))); 509 out.print("," + (context.getAssignments().isEmpty() || pref == 0.0 ? "" : new DecimalFormat("0.0").format(pref / context.getAssignments().size()))); 510 out.print("," + new DecimalFormat("0.0").format(100.0 * context.countBackToBackPercentage())); 511 out.print("," + (diffLinks <= 0 ? "" : diffLinks)); 512 for (TeachingAssignment ta : context.getAssignments()) { 513 String link = getLink(ta.variable()); 514 out.print("," + ta.variable().getCourse() + " " + ta.variable().getSections().get(0).getSectionType() + " " + ta.variable().getSections().get(0).getTime().getName(true) + (link == null ? "" : " " + link)); 515 } 516 out.println(); 517 } 518 out.flush(); 519 out.close(); 520 521 out = new PrintWriter(new File(dir, "input-courses.csv")); 522 Set<String> levels = new TreeSet<String>(); 523 for (TeachingRequest.Variable request : variables()) { 524 for (Preference<Attribute> p: request.getRequest().getAttributePreferences()) 525 levels.add(p.getTarget().getAttributeName()); 526 } 527 out.print("Course,Type,Load"); 528 for (String level: levels) 529 out.print("," + level); 530 out.println(); 531 Set<String> courses = new HashSet<String>(); 532 for (TeachingRequest.Variable request : variables()) { 533 if (courses.add(request.getCourse() + "," + request.getSections().get(0).getSectionType())) { 534 out.print(request.getCourse().getCourseName() + "," + request.getSections().get(0).getSectionType() + "," + request.getRequest().getLoad()); 535 for (String level: levels) { 536 int pref = 0; 537 for (Preference<Attribute> p: request.getRequest().getAttributePreferences()) 538 if (p.getTarget().getAttributeName().equals(level)) pref = p.getPreference(); 539 out.print("," + (pref == 0 ? "" : -pref)); 540 } 541 out.println(); 542 } 543 } 544 out.flush(); 545 out.close(); 546 } 547 548 public static void main(String[] args) throws Exception { 549 DataProperties config = new DataProperties(); 550 config.load(MathTest.class.getClass().getResourceAsStream("/org/cpsolver/instructor/test/math.properties")); 551 config.putAll(System.getProperties()); 552 ToolBox.configureLogging(); 553 554 new MathTest(config).execute(); 555 } 556}