Constraint Satisfaction Problems (CSP) in AI

Last Updated : 1 Sep, 2026

A Constraint Satisfaction Problem is a mathematical problem where the objective is to assign values to variables such that all the constraints are satisfied. Many AI applications use CSPs to solve decision-making problems. Common applications of CSPs include:

  • Scheduling: It assigns resources like employees or equipment while respecting time and availability constraints.
  • Planning: Organize tasks with specific deadlines or sequences.
  • Resource Allocation: Distributing resources efficiently without overuse
frame_3291

Components

1. Variables: Things we need to find values for. For example, in a Sudoku puzzle each empty cell is a variable that needs a number.

2. Domains: The set of possible values that a variable can have. In Sudoku the domain for each cell is the numbers 1 to 9.

3. Constraints: The rules that restrict how variables can be assigned values. There are different types of constraints:

  • Unary: Apply to a single variable like "this cell cannot be 5".
  • Binary: Involve two variables like "these two cells cannot have the same number".
  • Higher-order: Involve three or more variables like "each row in Sudoku must have all numbers from 1 to 9 without repetition".

Types

CSPs can be classified based on the number and importance of their constraints:

  1. Binary CSPs: Each constraint involves only two variables. Like in a scheduling problem the constraint could specify that task A must be completed before task B.
  2. Non-Binary CSPs: Involve more than two variables. For instance in a seating arrangement problem a constraint could state that three people cannot sit next to each other.
  3. Hard and Soft Constraints: Hard constraints must be strictly satisfied while soft constraints can be violated but at a certain cost. This is often used in real-world applications where not all constraints are equally important.

Representation

A constraint can be represented using a scope and a relation:

  • Scope: The variables involved in the constraint.
  • Relation: The valid combinations of values for those variables.

Example: For two variables V1 and V2, a constraint such as V1 \neq V2 means that the two variables cannot have the same value.

Solving CSPs Efficiently

CSPs use search and constraint-based techniques to find assignments that satisfy all constraints. Common approaches:

1. Backtracking Algorithm

A depth-first search method that assigns values to variables and backtracks when an assignment violates a constraint.

Working:

  • Select an unassigned variable and assign a value.
  • Continue assigning values to other variables.
  • If a constraint is violated, backtrack and try another value.
  • Continue until a solution is found or all possibilities are exhausted.

Backtracking is simple and effective for many CSPs, but it can become expensive for large search spaces.

2. Forward-Checking Algorithm

Improves backtracking by checking the domains of unassigned neighboring variables after each assignment.

Working:

  • Assign a value to a variable.
  • Remove inconsistent values from the domains of neighboring variables.
  • If any domain becomes empty, backtrack immediately.
  • Continue until a solution is found.

This reduces unnecessary exploration compared with basic backtracking.

3. Constraint Propagation Algorithms

Reduces the search space by repeatedly removing values that cannot satisfy the constraints.

Working:

  • Apply constraints between related variables.
  • Remove values that lead to inconsistent assignments.
  • Propagate these changes to other variables.
  • Continue until no more values can be removed or a solution is found.

Constraint propagation is often combined with backtracking to solve CSPs more efficiently.

Example: Solving Sudoku with CSP (Backtracking Approach)

Step 1: Define the Problem (Sudoku Puzzle Setup)

We represent the Sudoku puzzle as a 9×9 grid, where 0 represents an empty cell. The print_sudoku() function displays the puzzle in a readable format.

Python
puzzle = [[5, 3, 0, 0, 7, 0, 0, 0, 0],
          [6, 0, 0, 1, 9, 5, 0, 0, 0],
          [0, 9, 8, 0, 0, 0, 0, 6, 0],
          [8, 0, 0, 0, 6, 0, 0, 0, 3],
          [4, 0, 0, 8, 0, 3, 0, 0, 1],
          [7, 0, 0, 0, 2, 0, 0, 0, 6],
          [0, 6, 0, 0, 0, 0, 2, 8, 0],
          [0, 0, 0, 4, 1, 9, 0, 0, 5],
          [0, 0, 0, 0, 8, 0, 0, 7, 9]]

def print_sudoku(puzzle):
    for i in range(9):
        if i % 3 == 0 and i != 0:
            print("- - - - - - - - - - - ")
        for j in range(9):
            if j % 3 == 0 and j != 0:
                print(" | ", end="")
            print(puzzle[i][j], end=" ")
        print()

print("Initial Sudoku Puzzle:\n")
print_sudoku(puzzle)

Output:

Initial-Sudoku-puzzle
Initial Sudoku Puzzle

Step 2: Create the CSP Solver Class

We create a CSP class to store the variables, domains and constraints. The solve() method starts the backtracking process.

Python
class CSP:
    def __init__(self, variables, domains, constraints):
        self.variables = variables
        self.domains = domains
        self.constraints = constraints
        self.solution = None

    def solve(self):
        assignment = {}
        self.solution = self.backtrack(assignment)
        return self.solution

    def backtrack(self, assignment):
        if len(assignment) == len(self.variables):
            return assignment

        var = self.select_unassigned_variable(assignment)
        for value in self.order_domain_values(var, assignment):
            if self.is_consistent(var, value, assignment):
                assignment[var] = value
                result = self.backtrack(assignment)
                if result is not None:
                    return result
                del assignment[var]
        return None

Step 3: Implement Helper Functions for Backtracking

We add helper methods to select an unassigned variable, order its possible values and check whether an assignment satisfies the constraints.

Python
  def select_unassigned_variable(self, assignment):
        unassigned_vars = [var for var in self.variables if var not in assignment]
        return min(unassigned_vars, key=lambda var: len(self.domains[var]))

  def order_domain_values(self, var, assignment):
        return self.domains[var]

  def is_consistent(self, var, value, assignment):
        for constraint_var in self.constraints[var]:
            if constraint_var in assignment and assignment[constraint_var] == value:
                return False
        return True

These methods must be indented inside the CSP class.

Step 4: Define Variables, Domains and Constraints

Each Sudoku cell is treated as a variable. Empty cells have values from 1 to 9 in their domains, while filled cells have their given value. Constraints ensure that cells in the same row, column or 3×3 subgrid contain different values.

Python
variables = [(i, j) for i in range(9) for j in range(9)]

domains = {
    var: set(range(1, 10)) if puzzle[var[0]][var[1]] == 0 else {puzzle[var[0]][var[1]]}
    for var in variables
}

constraints = {}

def add_constraint(var):
    constraints[var] = []
    for i in range(9):
        if i != var[0]:
            constraints[var].append((i, var[1]))  
        if i != var[1]:
            constraints[var].append((var[0], i))  
    sub_i, sub_j = var[0] // 3, var[1] // 3
    for i in range(sub_i * 3, (sub_i + 1) * 3):
        for j in range(sub_j * 3, (sub_j + 1) * 3):
            if (i, j) != var:
                constraints[var].append((i, j))  

for var in variables:
    add_constraint(var)

Step 5: Solve the Sudoku Puzzle Using CSP

We create a CSP object using the Sudoku variables, domains and constraints. The solve() method uses backtracking to find a valid assignment, which is then converted back into a 9×9 Sudoku grid.

Python
csp = CSP(variables, domains, constraints)
sol = csp.solve()

solution = [[0 for _ in range(9)] for _ in range(9)]
for (i, j), val in sol.items():
    solution[i][j] = val

print("\n******* Solution *******\n")
print_sudoku(solution)

Output:

Screenshot-2025-05-04-130400
Output

You can download the source code from here.

Applications

  1. Scheduling: Assigning employees, rooms or resources while satisfying time and availability constraints.
  2. Puzzle Solving: Solving Sudoku, crosswords and N-Queens by representing puzzle elements as variables and constraints.
  3. Configuration: Selecting compatible components for products or systems, such as computer configurations.
  4. Robotics and Planning: Planning robot movements and tasks while avoiding obstacles and satisfying operational constraints.
  5. Natural Language Processing: Applying linguistic constraints to tasks such as sentence parsing and grammatical analysis.

Challenges

  1. Scalability: Large numbers of variables and constraints can create a very large search space.
  2. Dynamic Constraints: Real-world problems may change over time, requiring the solution to be updated.
  3. No Feasible Solution: Strict or conflicting constraints may make it impossible to find a valid assignment.
Comment

Explore