Expert System for Picking Outfits (#1)

This is the first of a series of posts walking through how I built a robot valet that picks clothing combinations. This post picks safe outfits, but structures the knowledge base that eventually can pick interesting outfits.

Picking my clothes isn’t that hard so why overthink it? I probably wont save enough time spent picking clothes to offset the time it took learn prolog and work on many versions of this knowledge base, but formalizing the clothes picking process means I can generate a week of outfits at once, add rules for how many days before my pants are dirty, and find clothes that don’t fit in any outfit which sounded kind of cool.

Prolog is a logic programming language that allows programmers to define facts and rules and search their program structure to see if particular goals can be satisfied.

% all sandwiches are tasty
tasty(X):- sandwich(X).

% caprese is a sandwich

% is a caprese tasty?
> true

Getting Started

Let’s start with how to represent an article of clothing. A really simple knowledge base might have


outfit(Shirt, Pants, Shoes):-

which can respond to queries like

?- shirt(X).
Shirt = hawkseason_shirt;
Shirt = red_tshirt_banana_republic

?- outfit(Shirt, Pants, Shoes).
Shirt = hawkseason_shirt,
Pants = blue_chinos_jcrew,
Shoes = chili_leather_loafers .
random outfit image/svg+xml

In swipl, after each way prolog generates to satisfy the query outfit(Shirt, Pants, Shoes). you can terminate the search with . or ask for more variable assignments that satisfy the query with ;.

This definition of outfit doesn’t really generate interesting combinations, it just generates all combinations including

Shirt = blue_button_down_untuckit,
Pants = blue_chinos_jcrew,
Shoes = blue_suede_loafers .

Getting more complicated with color

Let’s go back to our “closet” and layer in some more information like color hue, shade, and formality.

shirt(blue_button_down_untuckit, dark).
shirt(red_tshirt_banana_republic, dark).
pants(blue_chinos_jcrew, dark).
pants(gray_chinos_jcrew, dark).
shoes(chili_leather_loafers, dark).
shoes(blue_suede_loafers, light).

outfit(Shirt, Pants, Shoes):-
  shirt(Shirt, ShirtShade),
  pants(Pant, PantShade),
  shoes(Shoe, ShoeShade),
  ShirtShade = ShoeShade,
  ShirtShade \= PantShade.

Now when prolog tests out an outfit like

Shirt = blue_button_down_untuckit
Pants = gray_chinos_jcrew
Shoes = chili_leather_loafers
dark outfit image/svg+xml

it will realize that ShirtShade is the same as PantShade and reject the outfit. Queried directly, that is

?- outfit(blue_button_down_untuckit,

With this sort of structure, it’s easy to add rules for concepts like formality or color. Actually color is a little trickier and worth some focus, but a simple representation and rules like PantColor \= ShirtColor, PantColor \= ShoeColor generates safe outfits, though fails to highlight some more interesting combinations.

balanced outfit image/svg+xml