What happens with the holes when composing semantic elements using MRS algebra?

I am reading the paper An Algebra for Semantic Construction in Constraint-based Grammars in order to assist me with my work of using MRSs to generate referring expressions with the ERG.

In Section 4 on Labeling holes, there’s a definition (Definition 6) provided for what I believe is how one would fill the subject hole of some lexical item.

It looks to me like the definition essentially states that:

  1. The hook of the composed SSEMENT is the hook of the “semantic functor” (i.e. the one whose hole is being filled)
  2. The hole for each label not equal to the subject after the composition is performed is the union of the holes for that label from both elements?
  3. The new bag of EPs is both bags of EPs combined
  4. The new list of EQs is the transitive closure of the EQs of both elements being composed plus the fact that there is a new identity between the hook of the semantic argument and the hole of the functor, thus filling the hole

I don’t actually understand what item 2 is getting at actually and would like some help understanding what it’s saying.

I can’t quite map the formalism in the definition to this, but what I think that should mean is that the set of holes of the result is the union of the holes of each of the inputs, minus the hole that just got filled.

Ah, I see.

That makes sense, but I also am unsure how then I would handle situations with multiple holes because it seems like I would need to “know” what holes the lexical item has in order to apply rules correctly.

Off the top of my head it’s difficult for me to think of a situation in a referring expression involving multiple holes. But for example if I were dealing with verbs instead, and had _give_v_1, which has (at least) two holes ( _give_v_1 : ARG0 e, ARG1 i, ARG2 u, [ ARG3 i ].), it seems that in the case of generation I would have to know which complement fills which hole, so just having an operator that fills a complement hole seems like it would result in possibilities where I put them in the wrong order sometimes.

I can’t immediately see how the paper addresses this, other than I think having different rules for comp1 and comp2.

So then I’m imagining say I had to generate give a gift to them … the way my algorithm is going to work is that first it would just create the EP for the head of the whole phrase, so give. Then it would go down the child nodes of that root node and build those phrases and then return back up to combine with the head. So my problem is when I go down to the gift node and apply the right rules to get a gift, how then when I come back up do I know that it belongs in ARG1 and not ARG2? I think I can see at least that putting to them in ARG1 would be unacceptable because it requires something of type i, but nothing would stop me from mistakenly initially putting a gift in ARG2. (Or if I did give me a gift then nothing would stop me from mixing that up either).

As I’m typing this I just had the thought that maybe whatever rule I would have in that case for my give node would just have to be smart enough to know which child is the recipient and which child is the thing given. In which case it could shake out something like this:

def build_give_mrs(give_node):
    give_mrs = ep('give_v_1')
    item_mrs = build_phrase(give_node.get_child_with_edge_label('item'))

    recipient_mrs = build_phrase(give_node.get_child_with_edge_label('recipient'))

    arg2_filled_mrs = fill_arg2(give_mrs, recipient_mrs)
    arg1_filled_mrs = fill_arg1(arg2_filled_mrs, item_mrs)

    return arg_1_filled_mrs

So in this case I have general rules that handle filling holes for an ARG1 or ARG2 but then I have a more “high level” rule for handling the graph and its structure that employs these other rules.

The issue I see here would be that this is perhaps too general and doesn’t account for whether filling the hole is scopal or not and requires adding a qeq constraint.

I suppose I’ll just post this now as I continue to ponder and see if there’s any feedback on this initial thought.

Update. I have a second idea:

Perhaps it would work to have three layers of rules.

  1. Lowest level rules: specific hole filling rules for the different argument slots, e.g. fill_arg1(head, argument) except that I have two versions of each of these: fill_arg1_intersective and fill_arg2_scopal where the scopal one adds the necessary qeq constraint).
  2. Mid level rules: somewhat general rules for different phenomena I need to cover (e.g. intersective_modification, quantifier, etc.
  3. High level rules: Rules particular to the actual graphs themselves. In theory, somebody who wants to use my generator setup for a different domain would be able to create their own rules that are themselves composed of just the mid level rules.

So going back to the give_v_1 example,


  • ep(predicate_label) – builds an MRS with just the EP of the given predicate label
  • fill_arg1_intersective(head, arg) – fill the ARG1 hole head
  • fill_arg2_intersective(head, arg) – fill the ARG2 hole of the head
  • fill_arg1_scopal(head, arg) – this would be needed for a gift I believe, that is the ARG1 of the quantifier needs to use this for filling its own hole. (Maybe using ‘head’ terminology doesn’t work here).
    I would also need to handle the to them which I don’t know what rule that would use but something like above.


  • indef_np(head) – uses fill_arg1_scopal to create an indefinite noun phrase with the head
  • to_pp(head) – somehow handles the to them prepositional phrase
  • ditransitive(head, arg1, arg2) – creates a ditransitive vp
    There may be others, but the idea behind the mid level rules is they are a little more “self explanatory” than the low level rules that handle all the nitty gritty details of linking up the hook with the holes, etc.


  • give_event(root_node) – a developer using this system who knows they have to handle generating from a graph that has give nodes that point to other nodes with appropriately named edges would write their own rule here and use the ditransitive rule to get it done. (And then pass off the child nodes to something else etc).

This seems to me like a good route but if there is anything obvious that’s going to break as a result of breaking it up this way then I’d love any thoughts!

A couple of quick thoughts:

  1. You definitely want to work bottom up. Each smallest MRS part (sement, or whatever you want to call it) will declare its holes. Then the combination rules are responsible for making sure that the holes of the combined sements are based on those from the constituent parts (minus any holes that are filled).

  2. In the case of the ERG, the syntax determines which hole is being filled. But you don’t have syntax, so yes, you need to put something in its place (e.g. smarter rules). These rules should be informed by what’s in your input world representation but also probably need to know something about English — e.g. that ARG2 of _give_v is the gift and ARG3 the recipient.

Is there a clear way to tell what’s a hole from the SEMI?

I initially thought that anything that wasn’t the ARG0 would be a hole, and that ARG0 was the variable for the lexical item itself (so for _give_v_1 : ARG0 e, ARG1 i, ARG2 u, [ ARG3 i ]., the ARG0 is the giving event, and then the rest of the ARGs are holes).

However this isn’t the case it seems, since for def_explicit_q the ARG0 gets identified with the thing its quantifying, so that makes ARG0 a hole as well, but I’m not sure how I would know which items this applies to just by looking at the SEMI.

I’d say anything but ARG0 is a hole in non-quantifiers; ARG0 and RSTR (but not BODY) are holes in quantifiers.