12.3 Putting it into Prolog

As we have seen, we only have to adapt steps 1 (the initialization of chart and agenda) and 2d (how new hypotheses are predicted) of the general algorithm to arrive either at a bottom-up or at a top-down parser.

That means that we can also reuse most of the code that we implemented in the last chapter for the bottom-up algorithm. In fact, we only have to change the predicates initialize_chart_bottomup/2 and initialize_agenda_bottomup/1 that take care of the initialization and the predicates make_new_arcs_bottomup/2 and predict_new_arcs_bottomup/2 that implement step 2d. Let's first look at the initialization predicates.

For top-down processing, we initially write not only the words and their position into the chart but also passive arcs giving us the categories of the words. initialize_chart_topdown/2 recurses through the input list, writes the approriate scan entries to the chart and then uses doall (see Chapter 10) to retrieve all categories for each word from the lexicon. For each of these categories it asserts a passive arc to the chart.

%%% initialize_chart_topdown(+sentence, +start node)
initialize_chart_topdown([], _).
initialize_chart_topdown([Word|Input], From) :-
        To is From + 1,
        assert(scan(From, To, Word)),
             (lex(Word,Cat), assert(arc(From,To,Cat,[Word],[]))
        initialize_chart_topdown(Input, To).

In the initial agenda we want to have all possible hypotheses of how a sentence can be built. We therefore use findall to find all rules that have s on the left hand side of the arrow and add and active arc from position 0 to position 0.

%%% initialize_agenda_topdown(-agenda)
initialize_agenda_topdown(Agenda) :-
        findall(arc(0, 0, s, [], RHS), s ---> RHS, Agenda).

Now, let's look at how new arcs are created. As in the bottom-up case, we apply step 2c to all arcs. Different than in the bottom-up case, we will apply step 2d only to active arcs. make_new_arcs_topdown/2 makes sure that apply_fundamental_rule/2 and predict_new_arcs_topdown/2 are applied appropriately depending on whether an active or a passive arc is coming in.

%%% make_new_arcs_topdown(+arc, -list of arcs)  
%%% 'arc' is active -> steps 2c and 2d apply.
make_new_arcs_topdown(Arc, NewArcs) :-
        apply_fundamental_rule(Arc, NewArcs1),
        predict_new_arcs_topdown(Arc, NewArcs2),
%%% 'arc' is passive -> only step 2c applies.
make_new_arcs_topdown(Arc, NewArcs) :-
        apply_fundamental_rule(Arc, NewArcs).

The fundamental rule is always the same, no matter whether we are parsing bottom-up or top-down. But predict_new_arcs_topdown/2 changes. The arcs that are coming in are active. ToFindCat is the category that they need next. predict_new_arcs_topdown/2 looks for all rules that have this category on the left hand side and creates new active edges for them. These active edges span positions J to J, i.e., they don't cover anything of the string, yet, and start in the position where the active edge ends.

%%% predict_new_arcs_topdown(+arc, -list of arcs)
predict_new_arcs_topdown(arc(_, J, _, _, [ToFindCat|_]), NewArcs) :-
        findall(arc(J, J, ToFindCat, [], RHS),
                ToFindCat ---> RHS,

You can find the whole code in active_chart_topdown.pl.

Patrick Blackburn and Kristina Striegnitz
Version 1.2.4 (20020829)