-
Notifications
You must be signed in to change notification settings - Fork 24
Why global actions are not the same for all instances? #8
Comments
I assume you're talking about the wikitables parser? You can see the optimization that is done here: allennlp-semparse/allennlp_semparse/domain_languages/wikitables_language.py Lines 68 to 102 in 937d594
(there are also a few other places in the constructor that are relevant, but what I highlighted is the bulk of it) The point is that if there are no columns in the table that are dates, we shouldn't ever consider date-based actions. |
Thanks! That makes sense. |
So, this kind of polymorphism is not something that we handle right now. We had some crazy logic for def my_func(a: Generic[X], b: Generic[X]) -> X:
... And a type hierarchy like this: class X:
pass
class X1:
pass
class X2:
pass What rules should be added to the grammar for |
So let's just consider the simplest case. Say I have two classes and assume no class hierarchy. class X1:
pass
class X2:
pass I want a function |
In fact, my need is just to define a JOIN function for my language. So the join function should take inputs of type <A,B> and type <B, C>, and then returns a output of type <A, C>. I think this is to some extent a common need, but now it seems kind of convoluted to define it. |
Or maybe I can try to solve it in another way, i.e., I can define multiple JOIN functions for different input types (e.g., JOIN1, JOIN2, JOIN3...), then the problem becomes is it possible for those functions with different names to all be represented as predicate 'JOIN' in logic forms? For the current implementation, it looks like you are using each function name directly as a predicate in production rules. But if I can unbind a predicate from the strict function name and define the representation for it more freely it will solve my problem, even I would need to define thousands or even millions of different JOIN functions. |
So, you have a few options:
It's not exactly the same, but I know that @benbogin did something somewhat similar with runtime constraints on productions in the grammar when producing joins in his text2sql work. You might have a look at how he did it in his code. He was using a parsimonious-based grammar instead of a |
Thanks for your explanation! So the first option will introduce multiple different predicates into my logic forms (e.g., 'JOIN1', 'JOIN2', 'JOIN3',...), right? That's what I don't want. I only want one predicate 'JOIN' in my logic forms. So maybe I should go with the second option? |
Yes, the first option introduces multiple predicates. When you have just a few, this is an easy way to accomplish what you're trying to do (we've done this a few times when we had two different possible types). When you have more than 10, this is probably not a good idea (though I'm not totally sure). It's also interesting to explore how this affects learnability - it pushes the type decision higher up in the syntax tree, which may or may not be helpful (again, I'm really not sure). There are all kinds of issues around how grammar design affects parsing performance and generalizability, and I don't think anyone has explored these at all. It would make for a really interesting research paper =). |
Just found another way to address my problem: class TestLanguage(DomainLanguage):
def __init__(self, ...):
...
for a in types: # types is the set of all possible types we want to define JOIN over it
for b in types:
for c in types:
def JOIN(x: Tuple[a, b], y: Tuple[b, c]) -> Tuple[a, c]:
...
self.add_predicate('JOIN', JOIN)
... This works perfectly for me. Logic forms generated from this language are naturally guaranteed to be type compatible, and there is no need to modify Edited: This will cause the following problem when calling |
Yes, this is related to option 2 that I mentioned above (the caveat that I gave was talking about exactly this error). It's actually challenging to implement this, because you need to do type inference on the arguments to the function to determine which type you actually want for a particular logical form. I only did very rudimentary type inference in |
I guess what I don't quite get about option 2 is how do we generate subtype production rules? For instance, in your example that |
If you look in the wikitables language, we register some constants with multiple types (this currently works; it just doesn't work for functions, which are more complicated to do type inference for). So we have a rule That's the basic idea; I can give more detail if you need it. I also only outlined how the very simplest case would work; this could get pretty complicated if you have a whole lot of other stuff going on in your type system. |
Hi, I have implemented a new |
Does your function result in the same action sequence as the existing function for our current |
I didn't change the order of the actions. I compared my algorithm on languages with single-type functions that can be handled by yours, and my algorithm generates exactly the same actions as yours. The only difference is that since it's possible to have different action sequences for a logical form in my scenario (it does make sense when you both have multi-typed constants and functions), my return type is |
There are two kinds of actions in allennlp semantic parsing framework, i.e., global actions and linked actions, where linked actions are instance-specific actions. Since global actions do not depend on a specific instance, so I expect possible global actions to be the same for all instances, however, when I printed them, I surprisingly found that global actions also vary from instance to instance. Why is that? Have you done some pruning over global actions based on each instance to optimize the search procedure?
The text was updated successfully, but these errors were encountered: