|
| 1 | +import cpmpy as cp |
| 2 | +from cpmpy.transformations.normalize import toplevel_list |
| 3 | +from ..answering_queries.constraint_oracle import ConstraintOracle |
| 4 | +from ..problem_instance import ProblemInstance, absvar |
| 5 | + |
| 6 | + |
| 7 | +def construct_zebra_problem(): |
| 8 | + """ |
| 9 | + :Description: The zebra puzzle is a well-known logic puzzle. Five houses, each of a different color, are occupied by men of |
| 10 | + different nationalities, with different pets, drinks and cigarettes. The puzzle is to find out who owns the zebra. |
| 11 | + The puzzle has 15 clues that help determine the solution. |
| 12 | + :return: a ProblemInstance object, along with a constraint-based oracle |
| 13 | + """ |
| 14 | + # Create a dictionary with the parameters |
| 15 | + parameters = {"grid_size": 5, "num_categories": 5} |
| 16 | + |
| 17 | + # Variables |
| 18 | + # Flattened array with 25 elements, representing 5 elements for each of the 5 categories |
| 19 | + grid = cp.intvar(1, 5, shape=(5, 5), name="grid") |
| 20 | + |
| 21 | + C_T = list() |
| 22 | + |
| 23 | + # Extract variables for readability |
| 24 | + ukr, norge, eng, spain, jap = grid[0, :] # Nationalities |
| 25 | + red, blue, yellow, green, ivory = grid[1,:] # Colors |
| 26 | + oldGold, parly, kools, lucky, chest = grid[2,:] # Cigarettes |
| 27 | + zebra, dog, horse, fox, snails = grid[3,:] # Pets |
| 28 | + coffee, tea, h2o, milk, oj = grid[4,:] # Drinks |
| 29 | + |
| 30 | + # Add all constraints |
| 31 | + C_T += [(eng == red)] # Englishman lives in the red house |
| 32 | + C_T += [(spain == dog)] # Spaniard owns the dog |
| 33 | + C_T += [(coffee == green)] # Coffee is drunk in the green house |
| 34 | + C_T += [(ukr == tea)] # Ukrainian drinks tea |
| 35 | + C_T += [(green == ivory + 1)] # Green house is immediately right of the ivory house |
| 36 | + C_T += [(oldGold == snails)] # OldGold smoker owns snails |
| 37 | + C_T += [(kools == yellow)] # Kools are smoked in the yellow house |
| 38 | + C_T += [(milk == 3)] # Milk is drunk in the middle house |
| 39 | + C_T += [(norge == 1)] # Norwegian lives in the first house |
| 40 | + C_T += [(abs(chest - fox) == 1)] # Chesterfield smoker lives next to the man with the fox |
| 41 | + C_T += [(abs(kools - horse) == 1)] # Kools are smoked in the house next to the house with the horse |
| 42 | + C_T += [(lucky == oj)] # Lucky smoker drinks orange juice |
| 43 | + C_T += [(jap == parly)] # Japanese smokes Parliaments |
| 44 | + C_T += [(abs(norge - blue) == 1)] # Norwegian lives next to the blue house |
| 45 | + |
| 46 | + # Each row must have different values |
| 47 | + for row in grid: |
| 48 | + C_T += list(cp.AllDifferent(row).decompose()) |
| 49 | + |
| 50 | + # Create the language: |
| 51 | + AV = absvar(2) # create abstract vars - as many as maximum arity |
| 52 | + |
| 53 | + # create abstract relations using the abstract vars |
| 54 | + lang = [AV[0] == AV[1], AV[0] != AV[1], AV[0] < AV[1], AV[0] > AV[1], AV[0] >= AV[1], AV[0] <= AV[1], |
| 55 | + abs(AV[0] - AV[1]) == 1, abs(AV[0] - AV[1]) != 1, AV[0] - AV[1] == 1, AV[1] - AV[0] == 1] + [AV[0] == constant for constant in range(1, 6)] + [AV[0] != constant for constant in range(1, 6)] |
| 56 | + |
| 57 | + instance = ProblemInstance(variables=grid, params=parameters, language=lang, name="zebra") |
| 58 | + |
| 59 | + oracle = ConstraintOracle(list(set(toplevel_list(C_T)))) |
| 60 | + |
| 61 | + |
| 62 | + |
| 63 | + return instance, oracle |
0 commit comments