diff --git a/src/main/java/org/example/se302/algorithm/CSPSolver.java b/src/main/java/org/example/se302/algorithm/CSPSolver.java index 822dd25..c116d07 100644 --- a/src/main/java/org/example/se302/algorithm/CSPSolver.java +++ b/src/main/java/org/example/se302/algorithm/CSPSolver.java @@ -7,17 +7,141 @@ import java.util.*; /** * CSP (Constraint Satisfaction Problem) Solver for Exam Scheduling. * - * This solver uses a backtracking algorithm with the following optimizations: - * - MRV (Minimum Remaining Values) heuristic for variable ordering - * - Degree heuristic as a tie-breaker - * - Forward checking for constraint propagation - * - Arc consistency (AC-3) for further pruning + *
+ * CSP Components:
+ * - Variables: Each course that needs an exam scheduled (X = {C1, C2, ..., Cn})
+ * - Domain: All possible (TimeSlot, Classroom) pairs (D = T × R)
+ * - Constraints: Rules that must be satisfied for a valid schedule
+ *
+ * Hard Constraints:
+ * - HC1: Classroom Conflict - A classroom can host only one exam at a time
+ * - HC2: Student Conflict - A student cannot have two exams at the same time
+ * - HC3: Capacity - Classroom must have sufficient capacity
+ *
+ *
+ *
+ * function BACKTRACKING-SEARCH(csp):
+ * return BACKTRACK({}, csp)
+ *
+ * function BACKTRACK(assignment, csp):
+ * if assignment is complete:
+ * return assignment
+ *
+ * var ← SELECT-UNASSIGNED-VARIABLE(csp, assignment) // MRV Heuristic
+ *
+ * for each value in ORDER-DOMAIN-VALUES(var, assignment, csp): // LCV Heuristic
+ * if value is consistent with assignment:
+ * add {var = value} to assignment
+ * result ← BACKTRACK(assignment, csp)
+ * if result ≠ failure:
+ * return result
+ * remove {var = value} from assignment // Backtrack
+ *
+ * return failure
+ *
+ *
+ *
+ * Also known as "Most Constrained Variable" or "Fail-First" heuristic.
+ *
+ * function SELECT-UNASSIGNED-VARIABLE(csp, assignment):
+ * unassigned ← {var ∈ VARIABLES(csp) | var ∉ assignment}
+ * best ← null
+ * minValues ← ∞
+ * maxDegree ← -1
+ *
+ * for each var in unassigned:
+ * remaining ← COUNT-LEGAL-VALUES(var, assignment, csp)
+ * degree ← COUNT-CONFLICTS(var, unassigned)
+ *
+ * if remaining < minValues:
+ * best ← var; minValues ← remaining; maxDegree ← degree
+ * else if remaining = minValues AND degree > maxDegree:
+ * best ← var; maxDegree ← degree
+ *
+ * return best
+ *
+ * Why MRV works:
+ * - Detects failures early (fail-fast principle)
+ * - If a variable has 0 remaining values → immediate backtrack
+ * - Significantly prunes the search tree
+ *
+ *
+ * + * function ORDER-DOMAIN-VALUES(var, assignment, csp): + * values ← DOMAIN(var) + * + * for each value in values: + * value.score ← 0 + * for each neighbor in NEIGHBORS(var): + * if neighbor ∉ assignment: + * for each neighborValue in DOMAIN(neighbor): + * if CONFLICTS(value, neighborValue): + * value.score ← value.score + 1 + * + * return SORT(values, by: score, order: ascending) + * + * Why LCV works: + * - Maximizes flexibility for future assignments + * - Leaves more options for remaining variables + * - Increases probability of finding a solution + *+ * + *
+ * TIME COMPLEXITY: + * ┌────────────────────────┬───────────┬────────────────────────────────────┐ + * │ Component │ Complexity│ Description │ + * ├────────────────────────┼───────────┼────────────────────────────────────┤ + * │ Worst Case │ O(d^n) │ d = domain size, n = variables │ + * │ Build Conflict Graph │ O(n²×s) │ n = courses, s = avg students │ + * │ MRV Selection │ O(n×d) │ Scan all vars, count legal values │ + * │ LCV Ordering │ O(d×m×d) │ d = domain, m = neighbors │ + * │ Consistency Check │ O(k) │ k = number of constraints │ + * └────────────────────────┴───────────┴────────────────────────────────────┘ + * + * SPACE COMPLEXITY: + * ┌────────────────────────┬───────────┬────────────────────────────────────┐ + * │ Component │ Complexity│ Description │ + * ├────────────────────────┼───────────┼────────────────────────────────────┤ + * │ Assignment Storage │ O(n) │ One assignment per course │ + * │ Conflict Graph │ O(n²) │ Worst case: all courses conflict │ + * │ Domain Storage │ O(t×r) │ t = time slots, r = classrooms │ + * │ Recursion Stack │ O(n) │ Maximum depth = number of courses │ + * └────────────────────────┴───────────┴────────────────────────────────────┘ + * + * PRACTICAL PERFORMANCE (with heuristics): + * ┌─────────────────────────┬─────────────────────┐ + * │ Scenario │ Expected Time │ + * ├─────────────────────────┼─────────────────────┤ + * │ Small (<50 courses) │ < 1 second │ + * │ Medium (50-200 courses) │ 1-30 seconds │ + * │ Large (200-500 courses) │ 30 sec - 5 minutes │ + * │ Very Large (>500) │ May need more opts │ + * └─────────────────────────┴─────────────────────┘ + *+ * + *
+ * Algorithm Steps: + * 1. Check if timeout exceeded + * 2. If all courses assigned → return solution + * 3. Select unassigned course using MRV heuristic + * 4. Order domain values using LCV heuristic + * 5. For each (timeSlot, classroom) value: + * a. If consistent with constraints → assign + * b. Recursively solve remaining courses + * c. If solution found → return + * d. Otherwise → backtrack (undo assignment) + * 6. Return null if no solution found + *+ * + * @param state Current schedule state + * @return Complete schedule if solution found, null otherwise */ private ScheduleState backtrack(ScheduleState state) { // Check timeout