Zebra puzzle

You are encouraged to solve this task according to the task description, using any language you may know.
The Zebra puzzle, a.k.a. Einstein's Riddle,
is a logic puzzle which is to be solved programmatically.



It has several variants, one of them this:

   There are five houses.
   The English man lives in the red house.
   The Swede has a dog.
   The Dane drinks tea.
   The green house is immediately to the left of the white house.
   They drink coffee in the green house.
   The man who smokes Pall Mall has birds.
   In the yellow house they smoke Dunhill.
   In the middle house they drink milk.
   The Norwegian lives in the first house.
   The man who smokes Blend lives in the house next to the house with cats.
   In a house next to the house where they have a horse, they smoke Dunhill.
   The man who smokes Blue Master drinks beer.
   The German smokes Prince.
   The Norwegian lives next to the blue house.
   They drink water in a house next to the house where they smoke Blend. 

The question is, who owns the zebra?

Additionally, list the solution for all the houses.

Optionally, show the solution is unique.



Related tasks

   Dinesman's multiple-dwelling problem
   Twelve statements


enum Colour, Nationality, Drink, Smoke, Pet
constant Colours = {"red","white","green","yellow","blue"},
         Nationalities = {"English","Swede","Dane","Norwegian","German"},
         Drinks = {"tea","coffee","milk","beer","water"},
         Smokes = {"Pall Mall","Dunhill","Blend","Blue Master","Prince"},
         Pets = {"dog","birds","cats","horse","zebra"},
         Sets = {Colours,Nationalities,Drinks,Smokes,Pets}
 
constant tagset5 = tagset(5)        -- {1,2,3,4,5}, oft-permuted
sequence perm = repeat(tagset5,5)   -- perm[1] is Colour of each house, etc
 
function house(integer i, string name)
    return find(find(name,Sets[i]),perm[i])
end function
 
function left_of(integer h1, integer h2)
    return (h1-h2)==1
end function
 
function next_to(integer h1, integer h2)
    return abs(h1-h2)==1
end function
 
procedure print_house(integer i)
    printf(1,"%d:%s,%s,%s,%s,%s\n",{i,
                                    Colours[perm[Colour][i]],
                                    Nationalities[perm[Nationality][i]],
                                    Drinks[perm[Drink][i]],
                                    Smokes[perm[Smoke][i]],
                                    Pets[perm[Pet][i]]})
end procedure
 
integer solutions = 0
sequence solperms = {}
atom t0 = time()
constant factorial5 = factorial(5)
for C=1 to factorial5 do
    perm[Colour] = permute(C,tagset5)
    if left_of(house(Colour,"green"),house(Colour,"white")) then
        for N=1 to factorial5 do
            perm[Nationality] = permute(N,tagset5)
            if house(Nationality,"Norwegian")==1
            and house(Nationality,"English")==house(Colour,"red") 
            and next_to(house(Nationality,"Norwegian"),house(Colour,"blue")) then
                for D=1 to factorial5 do
                    perm[Drink] = permute(D,tagset5)
                    if house(Nationality,"Dane")==house(Drink,"tea")
                    and house(Drink,"coffee")==house(Colour,"green")
                    and house(Drink,"milk")==3 then
                        for S=1 to factorial5 do
                            perm[Smoke] = permute(S,tagset5)
                            if house(Colour,"yellow")==house(Smoke,"Dunhill")
                            and house(Nationality,"German")==house(Smoke,"Prince")
                            and house(Smoke,"Blue Master")==house(Drink,"beer")
                            and next_to(house(Drink,"water"),house(Smoke,"Blend")) then
                                for P=1 to factorial5 do
                                    perm[Pet] = permute(P,tagset5)
                                    if house(Nationality,"Swede")==house(Pet,"dog")
                                    and house(Smoke,"Pall Mall")==house(Pet,"birds")
                                    and next_to(house(Smoke,"Blend"),house(Pet,"cats"))
                                    and next_to(house(Pet,"horse"),house(Smoke,"Dunhill")) then
                                        for i=1 to 5 do
                                            print_house(i)
                                        end for
                                        solutions += 1
                                        solperms = append(solperms,perm)
                                    end if
                                end for
                            end if
                        end for
                    end if
                end for
            end if
        end for
    end if
end for
printf(1,"%d solution%s found (%3.3fs).\n",{solutions,iff(solutions>1,"s",""),time()-t0})
for i=1 to length(solperms) do
    perm = solperms[i]
    printf(1,"The %s owns the Zebra\n",{Nationalities[house(Pet,"zebra")]})
end for
