Tutorial 2.2: Learning Lexicon Entries in a Combinatory Categorial Grammar#

[1]:
import jacinle
from tabulate import tabulate
[2]:
# From tutorial/1-dsl/1-types-and-functions
from concepts.dsl.dsl_types import ValueType, ConstantType, BOOL, FLOAT32, VectorValueType
from concepts.dsl.dsl_functions import Function, FunctionTyping
from concepts.dsl.function_domain import FunctionDomain

t_item = ValueType('item')
t_item_set = ValueType('item_set')
t_concept_name = ConstantType('concept_name')
t_shape = ValueType('shape')
t_color = ValueType('color')
t_size = VectorValueType(FLOAT32, 3, alias='size')

domain = FunctionDomain()
domain.define_type(t_item)
domain.define_type(t_item_set)
domain.define_type(t_concept_name)
domain.define_type(t_color)
domain.define_type(t_shape)
domain.define_type(t_size)
domain.define_function(Function('scene', FunctionTyping[t_item_set]()))
domain.define_function(Function('filter_color', FunctionTyping[t_item_set](t_item_set, t_concept_name)))
domain.define_function(Function('filter_shape', FunctionTyping[t_item_set](t_item_set, t_concept_name)))
domain.define_function(Function('unique', FunctionTyping[t_item](t_item_set)))
domain.define_function(Function('color_of', FunctionTyping[t_color](t_item)))
domain.define_function(Function('shape_of', FunctionTyping[t_shape](t_item)))
domain.define_function(Function('size_of', FunctionTyping[t_size](t_item)))
domain.define_function(Function('same_color', FunctionTyping[BOOL](t_color, t_color)))
domain.define_function(Function('same_shape', FunctionTyping[BOOL](t_shape, t_shape)))
domain.define_function(Function('same_size', FunctionTyping[BOOL](t_size, t_size)))
[2]:
Function<same_size(#0: size, #1: size) -> bool>
[3]:
# From tutorial/2-ccg/1-parsing
from concepts.language.ccg.syntax import CCGSyntaxSystem

ss = CCGSyntaxSystem()
ss.define_primitive_type('S')
ss.define_primitive_type('N')
[4]:
from concepts.language.ccg.search import CCGSyntaxEnumerativeSearcher
syntax_searcher = CCGSyntaxEnumerativeSearcher(ss, starting_symbols=['S'])
[5]:
syntax_searcher.gen(2)
[5]:
[CCGSyntaxSearchResult(syntax=CCGPrimitiveSyntaxType<S>, depth=1),
 CCGSyntaxSearchResult(syntax=CCGPrimitiveSyntaxType<N>, depth=1),
 CCGSyntaxSearchResult(syntax=CCGComposedSyntaxType<S/N>, depth=2),
 CCGSyntaxSearchResult(syntax=CCGComposedSyntaxType<S\N>, depth=2),
 CCGSyntaxSearchResult(syntax=CCGComposedSyntaxType<N/N>, depth=2),
 CCGSyntaxSearchResult(syntax=CCGComposedSyntaxType<N\N>, depth=2)]
[6]:
from concepts.language.ccg.search import CCGSemanticsEnumerativeSearcher
semantics_searcher = CCGSemanticsEnumerativeSearcher(domain)
[7]:
from concepts.dsl.dsl_types import FormatContext
search_results = semantics_searcher.gen(max_depth=2)

# Use the FormatContext to format the function forms in a "lambda-function" style.
with FormatContext(function_format_lambda=True).as_default():
    print(tabulate(
        [(s.semantics.value, s.depth, s.nr_constant_arguments, s.nr_variable_arguments) for s in search_results],
        headers=['form', 'depth', '#consts', '#vars']
    ))
form                                                depth    #consts    #vars
------------------------------------------------  -------  ---------  -------
scene()                                                 1          0        0
lam #0.lam #1.filter_color(V::#0, V::#1)                1          1        1
lam #0.lam #1.filter_shape(V::#0, V::#1)                1          1        1
lam #0.unique(V::#0)                                    1          0        1
lam #0.color_of(V::#0)                                  1          0        1
lam #0.shape_of(V::#0)                                  1          0        1
lam #0.size_of(V::#0)                                   1          0        1
lam #0.lam #1.same_color(V::#0, V::#1)                  1          0        2
lam #0.lam #1.same_shape(V::#0, V::#1)                  1          0        2
lam #0.lam #1.same_size(V::#0, V::#1)                   1          0        2
lam #0.filter_color(scene(), V::#0)                     2          1        0
lam #0.filter_shape(scene(), V::#0)                     2          1        0
unique(scene())                                         2          0        0
lam #0.lam #1.unique(filter_color(V::#0, V::#1))        2          1        1
lam #0.lam #1.unique(filter_shape(V::#0, V::#1))        2          1        1
lam #0.color_of(unique(V::#0))                          2          0        1
lam #0.shape_of(unique(V::#0))                          2          0        1
lam #0.size_of(unique(V::#0))                           2          0        1
lam #0.lam #1.same_color(color_of(V::#0), V::#1)        2          0        2
lam #0.lam #1.same_color(V::#1, color_of(V::#0))        2          0        2
lam #0.lam #1.same_shape(shape_of(V::#0), V::#1)        2          0        2
lam #0.lam #1.same_shape(V::#1, shape_of(V::#0))        2          0        2
lam #0.lam #1.same_size(size_of(V::#0), V::#1)          2          0        2
lam #0.lam #1.same_size(V::#1, size_of(V::#0))          2          0        2
[8]:
from concepts.language.ccg.grammar import CCG
ccg = CCG(domain, ss)
ccg.add_entry_simple('red', ss['N/N'], domain.lam(lambda x: domain.f_filter_color(x, 'red')))
ccg.add_entry_simple('object', ss['N'], domain.lam(lambda: domain.f_scene()))
[9]:
from concepts.language.ccg.learning import by_parsing
learning_results = by_parsing(
    ccg, 'blue object',
    syntax_searcher=syntax_searcher,
    semantics_searcher=semantics_searcher,
    syntax_searcher_kwargs={'max_depth': 2},
    semantics_searcher_kwargs={'max_depth': 2},
    bind_concepts=True  # If true, the algorithm will automatically create "new" concepts!
)

# Prettify the learning results
learning_results_table = list()
for r in learning_results:
    assert len(r.words) == 1  # there is only one novel word.

    learning_results_table.append((
        r.lexicons[0].syntax, r.lexicons[0].semantics.value, r.parsing_results[0].semantics.value
    ))

print('Learning results for "blue"')
with FormatContext(function_format_lambda=True).as_default():
    print(tabulate(learning_results_table, headers=['syntax', 'semantics', 'parsing ("blue object")']))
Learning results for "blue"
syntax    semantics                                 parsing ("blue object")
--------  ----------------------------------------  ----------------------------------------------------------
S/N       lam #0.filter_color(V::#0, blue)          filter_color(scene(), V(blue, dtype=concept_name))
S/N       lam #0.filter_shape(V::#0, blue)          filter_shape(scene(), V(blue, dtype=concept_name))
S/N       lam #0.unique(V::#0)                      unique(scene())
S/N       lam #0.unique(filter_color(V::#0, blue))  unique(filter_color(scene(), V(blue, dtype=concept_name)))
S/N       lam #0.unique(filter_shape(V::#0, blue))  unique(filter_shape(scene(), V(blue, dtype=concept_name)))
S/N       lam #0.color_of(unique(V::#0))            color_of(unique(scene()))
S/N       lam #0.shape_of(unique(V::#0))            shape_of(unique(scene()))
S/N       lam #0.size_of(unique(V::#0))             size_of(unique(scene()))
[10]:
# TODO: Learning with "by_grounding"