Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prolog - Using terms to represent and access complex, nested data

my_computer([
    case([
        motherboard([board(plastic),ports(metal),slots(plastic),capacitors(plastic)]),
        power_supply_unit([casing(metal),cables(plastic),connectors(plastic),capacitors(plastic),fan(plastic),transformer(metal)]),
        central_processing_unit([board(plastic),fan(plastic),heatsink(metal)]),
        random_access_memory([board(plastic)]),
        graphics_processing_unit([board(plastic),ports(metal),capacitors(plastic),fan(plastic),heatsink(metal)])
    ]),
    monitor([
        lcd_screen(plastic),inverter(plastic),frame(plastic)
    ]),
    keyboard([
        key(plastic),frame(plastic),cable(plastic)
    ]),
    mouse([
        key(plastic),wheel(plastic),casing(plastic),cable(plastic)
    ])
]).

What should I do to in order to run questions like monitor(X). or motherboard(X) to give one or all layers of (sub)materials (Like my_computer(X). would do) ?

Would the code below be more useful for asking such questions? Question about one layer of submaterials is answered easily this way.

my_computer([case,monitor,keyboard,mouse]).
    case([motherboard,power_supply_unit,central_processing_unit,random_access_memory,graphics_processing_unit]).
        motherboard([board,ports,slots,capacitors]).
        power_supply_unit([casing,cables,connectors,capacitors,fan,transformer]).
        central_processing_unit([board,fan,heatsink]).
        random_access_memory([board]).
        graphics_processing_unit([board,ports,capacitors,fan,heatsink]).
    monitor([lcd_screen,inverter,frame]).
    keyboard(keys,frame,cable).
    mouse([keys,wheel,casing,cable]).
like image 917
Crownless Avatar asked Feb 24 '15 16:02

Crownless


1 Answers

The short answer to your questions would be:

monitor(X) :-
    my_computer([_, monitor(X), _, _]).

And similarly for keyboard or mouse, etc. The motherboard would be a layer deeper:

motherboard(X) :-
    my_computer([case([motherboard(X), _, _, _, _), _, _, _]).

These predicates of course assume a fixed structure. If you wanted it a bit more general, you could do a more elaborate "hunt" for the embedded functors (monitor, motherboard, etc).

Depending upon your broader application goals, it's not clear to me that this is the best representation of the data. Good enough for now, but context might want to take it in a different direction.


Here's another approach, thinking of the data as individual facts which imply a tree relationship. Basically just has relationships. Separate the "material" facts as material(Item, Type):
item(my_computer, case).
item(my_computer, monitor).
item(my_computer, keyboard).
item(my_computer, mouse).

item(case, motherboard).
item(case, power_supply_unit).
item(case, central_processing_unit).
item(case, random_access_memory).
item(case, graphics_processing_unit).

item(motherboard, board).
item(motherboard, ports).
item(motherboard, slots).
item(motherboard, capacitors).

item(power_supply_unit, casing).
item(power_supply_unit, cable).
item(power_supply_unit, connectors).
item(power_supply_unit, capacitors).
item(power_supply_unit, fan).
item(power_supply_unit, transformer).

item(central_processing_unit, board).
item(central_processing_unit, fan).
item(central_processing_unit, heatsink).

item(random_access_memory, board).

item(graphics_processing_unit, board).
item(graphics_processing_unit, ports).
item(graphics_processing_unit, capacitors).
item(graphics_processing_unit, fan).
item(graphics_processing_unit, heatsink).

item(monitor, lcd_screen).
item(monitor, inverter).
item(monitor, frame).

item(keyboard, key).
item(keyboard, frame).
item(keyboard, cable).

item(mouse, key).
item(mouse, wheel).
item(mouse, casing).
item(mouse, cable).

material(board, plastic).
material(slots, plastic).
material(capacitors, plastic).
material(ports, metal).
material(casing, metal).
material(cable, plastic).
material(connectors, plastic).
material(fan, plastic).
material(heatsink, metal).
material(lcd_screen, plastic).
material(inverter, plastic).
material(frame, plastic).
material(key, plastic).
material(cable, plastic).

Then you can define a predicate to generate the tree for whatever level you wish. Here's an example that does it in the form of terms (not lists):

structure(Item, Structure) :-
    (   item(Item, _)
    ->  findall(T, (item(Item, R), structure(R, T)), Rs),
        Structure =.. [Item |Rs]
    ;   Structure = Item
    ).

So then:

:- structure(case, S).
S = case(motherboard(board,ports,slots,capacitors),
         power_supply_unit(casing,cable,connectors,capacitors,fan,transformer),
         central_processing_unit(board,fan,heatsink),
         random_access_memory(board),
         graphics_processing_unit(board,ports,capacitors,fan,heatsink)
        )

This could easily be changed to provide results in a list form instead. For example, here's a predicate that takes the above facts and gives the form you originally presented in your question:

structure(Item, Tree) :-
    (   item(Item, _)
    ->  findall(T, (item(Item, R), structure(R, T)), Rs),
        Tree =.. [Item, Rs]
    ;   material(Item, Material),
        Tree =.. [Item, Material]
    ).

And the item becomes a trivial result for a where_used(Item, Parent) predicate:

where_used(Item, Parent) :-
    item(Parent, Item).

Again, it all depends upon how you want to use and manage the data.

like image 119
lurker Avatar answered Oct 27 '22 07:10

lurker