Tutorial 2.3: Basics of Neuro-Symbolic 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/1-dsl/2-execution
from dataclasses import dataclass, field
from typing import Tuple, List
from concepts.dsl.executors.function_domain_executor import FunctionDomainExecutor

@dataclass
class Item(object):
    color: str
    shape: str
    size: Tuple[float, float, float]


@dataclass
class Scene(object):
    items: List[Item]

class Executor(FunctionDomainExecutor):
    def scene(self):
        return self.grounding.items
    def filter_color(self, inputs, color_name):
        return [o for o in inputs if o.color == color_name]
    def filter_shape(self, inputs, shape_name):
        return [o for o in inputs if o.shape == shape_name]
    def unique(self, inputs):
        assert len(inputs) == 1
        return inputs[0]
    def color_of(self, obj):
        return obj.color
    def shape_of(self, obj):
        return obj.shape
    def size_of(self, obj):
        return obj.size
    def same_color(self, c1, c2):
        return c1 == c2
    def same_shape(self, s1, s2):
        return s1 == s2
    def same_size(self, z1, z2):
        return all(abs(sz1 - sz2) < 0.1 for sz1, sz2 in zip(z1, z2))

executor = Executor(domain)
11 22:40:38 Function scene automatically registered.
11 22:40:38 Function filter_color automatically registered.
11 22:40:38 Function filter_shape automatically registered.
11 22:40:38 Function unique automatically registered.
11 22:40:38 Function color_of automatically registered.
11 22:40:38 Function shape_of automatically registered.
11 22:40:38 Function size_of automatically registered.
11 22:40:38 Function same_color automatically registered.
11 22:40:38 Function same_shape automatically registered.
11 22:40:38 Function same_size automatically registered.
[4]:
from concepts.language.ccg.composition import CCGCompositionType
from concepts.language.neural_ccg.grammar import NeuralCCGSyntaxType, NeuralCCGConjSyntaxType
from concepts.language.neural_ccg.grammar import NeuralCCGSemantics, NeuralCCGGroundingFunction
[5]:
candidate_syntax_types = list(NeuralCCGSyntaxType.iter_from_function(domain.f_filter_color, nr_used_arguments=1))
candidate_syntax_types
[5]:
[(NeuralCCGSyntaxType<item_set/item_set>,
  Function<def filter_color(#0: item_set, #1: concept_name): return filter_color(V::#0, V::#1)>),
 (NeuralCCGSyntaxType<item_set\item_set>,
  Function<def filter_color(#0: item_set, #1: concept_name): return filter_color(V::#0, V::#1)>)]
[6]:
syn1 = candidate_syntax_types[0][0]
syn2 = NeuralCCGSyntaxType(domain.t_item_set)
print(syn1.return_type, syn1.argument_types, syn1.linearization)
print(syn2.return_type, syn2.argument_types, syn2.linearization)
item_set (ValueType<item_set>,) (LinearizationTuple(index=0, direction=<CCGCompositionDirection.RIGHT: 'right'>),)
item_set () ()
[7]:
syn1.compose(syn2, CCGCompositionType.FORWARD_APPLICATION)
[7]:
NeuralCCGSyntaxType<item_set>
[8]:
syn3 = NeuralCCGConjSyntaxType('AND')
[9]:
# syn1 (syn3 syn1)
syn3.compose(syn1, CCGCompositionType.COORDINATION)
[9]:
CCGCoordinationImmNode(conj=NeuralCCGConjSyntaxType<AND>, rhs=NeuralCCGSyntaxType<item_set/item_set>)
[10]:
# (syn1 (syn3 syn1))
syn1.compose(syn3.compose(syn1, CCGCompositionType.COORDINATION), CCGCompositionType.COORDINATION)
[10]:
NeuralCCGSyntaxType<item_set/item_set>
[11]:
from concepts.dsl.learning.function_domain_search import FunctionDomainExpressionEnumerativeSearcher
from concepts.language.neural_ccg.search import NeuralCCGLexiconEnumerativeSearcher
[12]:
expression_searcher = FunctionDomainExpressionEnumerativeSearcher(domain)
candidate_expressions = expression_searcher.gen()
[13]:
for result in candidate_expressions:
    print(result.expression)
def __lambda__(): return scene()
def __lambda__(#0: item_set, #1: concept_name): return filter_color(V::#0, V::#1)
def __lambda__(#0: item_set, #1: concept_name): return filter_shape(V::#0, V::#1)
def __lambda__(#0: item_set): return unique(V::#0)
def __lambda__(#0: item): return color_of(V::#0)
def __lambda__(#0: item): return shape_of(V::#0)
def __lambda__(#0: item): return size_of(V::#0)
def __lambda__(#0: color, #1: color): return same_color(V::#0, V::#1)
def __lambda__(#0: shape, #1: shape): return same_shape(V::#0, V::#1)
def __lambda__(#0: size, #1: size): return same_size(V::#0, V::#1)
def __lambda__(#0: concept_name): return filter_color(scene(), V::#0)
def __lambda__(#0: concept_name): return filter_shape(scene(), V::#0)
def __lambda__(): return unique(scene())
def __lambda__(#0: item_set, #1: concept_name): return unique(filter_color(V::#0, V::#1))
def __lambda__(#0: item_set, #1: concept_name): return unique(filter_shape(V::#0, V::#1))
def __lambda__(#0: item_set): return color_of(unique(V::#0))
def __lambda__(#0: item_set): return shape_of(unique(V::#0))
def __lambda__(#0: item_set): return size_of(unique(V::#0))
def __lambda__(#0: item, #1: color): return same_color(color_of(V::#0), V::#1)
def __lambda__(#0: color, #1: item): return same_color(V::#0, color_of(V::#1))
def __lambda__(#0: item, #1: shape): return same_shape(shape_of(V::#0), V::#1)
def __lambda__(#0: shape, #1: item): return same_shape(V::#0, shape_of(V::#1))
def __lambda__(#0: item, #1: size): return same_size(size_of(V::#0), V::#1)
def __lambda__(#0: size, #1: item): return same_size(V::#0, size_of(V::#1))
def __lambda__(#0: concept_name): return unique(filter_color(scene(), V::#0))
def __lambda__(#0: concept_name): return unique(filter_shape(scene(), V::#0))
def __lambda__(): return color_of(unique(scene()))
def __lambda__(#0: item_set, #1: concept_name): return color_of(unique(filter_color(V::#0, V::#1)))
def __lambda__(#0: item_set, #1: concept_name): return color_of(unique(filter_shape(V::#0, V::#1)))
def __lambda__(): return shape_of(unique(scene()))
def __lambda__(#0: item_set, #1: concept_name): return shape_of(unique(filter_color(V::#0, V::#1)))
def __lambda__(#0: item_set, #1: concept_name): return shape_of(unique(filter_shape(V::#0, V::#1)))
def __lambda__(): return size_of(unique(scene()))
def __lambda__(#0: item_set, #1: concept_name): return size_of(unique(filter_color(V::#0, V::#1)))
def __lambda__(#0: item_set, #1: concept_name): return size_of(unique(filter_shape(V::#0, V::#1)))
def __lambda__(#0: item_set, #1: color): return same_color(color_of(unique(V::#0)), V::#1)
def __lambda__(#0: color, #1: item_set): return same_color(V::#0, color_of(unique(V::#1)))
def __lambda__(#0: item_set, #1: shape): return same_shape(shape_of(unique(V::#0)), V::#1)
def __lambda__(#0: shape, #1: item_set): return same_shape(V::#0, shape_of(unique(V::#1)))
def __lambda__(#0: item_set, #1: size): return same_size(size_of(unique(V::#0)), V::#1)
def __lambda__(#0: size, #1: item_set): return same_size(V::#0, size_of(unique(V::#1)))
def __lambda__(#0: item, #1: item): return same_color(color_of(V::#0), color_of(V::#1))
def __lambda__(#0: item, #1: item): return same_shape(shape_of(V::#0), shape_of(V::#1))
def __lambda__(#0: item, #1: item): return same_size(size_of(V::#0), size_of(V::#1))
[14]:
lexicon_searcher = NeuralCCGLexiconEnumerativeSearcher(candidate_expressions, executor)
candidate_lexicon_entries = lexicon_searcher.gen()
[15]:
candidate_lexicon_entries_table = list()
for result in candidate_lexicon_entries[:20]:
    candidate_lexicon_entries_table.append((str(result.syntax), str(result.semantics)))
print(tabulate(candidate_lexicon_entries_table, headers=['syntax', 'semantics']))

print(f'In total: {len(candidate_lexicon_entries)} lexicon entries.')
syntax             semantics
-----------------  ---------------------------------------------------------------------------------
item_set           def __lambda__(): return scene()
item_set/item_set  def __lambda__(#0: item_set, #1: concept_name): return filter_color(V::#0, V::#1)
item_set\item_set  def __lambda__(#0: item_set, #1: concept_name): return filter_color(V::#0, V::#1)
item_set/item_set  def __lambda__(#0: item_set, #1: concept_name): return filter_shape(V::#0, V::#1)
item_set\item_set  def __lambda__(#0: item_set, #1: concept_name): return filter_shape(V::#0, V::#1)
item/item_set      def __lambda__(#0: item_set): return unique(V::#0)
item\item_set      def __lambda__(#0: item_set): return unique(V::#0)
color/item         def __lambda__(#0: item): return color_of(V::#0)
color\item         def __lambda__(#0: item): return color_of(V::#0)
shape/item         def __lambda__(#0: item): return shape_of(V::#0)
shape\item         def __lambda__(#0: item): return shape_of(V::#0)
size/item          def __lambda__(#0: item): return size_of(V::#0)
size\item          def __lambda__(#0: item): return size_of(V::#0)
bool/color/color   def __lambda__(#0: color, #1: color): return same_color(V::#1, V::#0)
bool\color/color   def __lambda__(#0: color, #1: color): return same_color(V::#1, V::#0)
bool\color\color   def __lambda__(#0: color, #1: color): return same_color(V::#1, V::#0)
bool/color/color   def __lambda__(#0: color, #1: color): return same_color(V::#0, V::#1)
bool\color/color   def __lambda__(#0: color, #1: color): return same_color(V::#0, V::#1)
bool\color\color   def __lambda__(#0: color, #1: color): return same_color(V::#0, V::#1)
bool/shape/shape   def __lambda__(#0: shape, #1: shape): return same_shape(V::#1, V::#0)
In total: 151 lexicon entries.