# Grow Grammar
#
# Grow formulas from solid entities. No floating relations are formed.
# This is more similar to the search method in Jonathan Berant's ACL2014 paper.
#
# Main Categories:
# - Set: a set of things
# - Map[Set s]: a mapping whose domain is s

################################################################
# Macros

(def @R reverse)
(def @type fb:type.object.type)
(def @row fb:type.row)
(def @numdate (union fb:type.number fb:type.datetime))

(def @next fb:row.row.next)
(def @index fb:row.row.index)
(def @p.num fb:cell.cell.number)
(def @p.date fb:cell.cell.date)
(def @p.num2 fb:cell.cell.num2)
(def @p.part fb:cell.cell.part)

################################################################
# Base Rules for Sets

################################
# Anchored Rules

# Fuzzy match the utterance phrase to a table cell (or part of cell)
(rule $Set ($PHRASE) (FuzzyMatchFn entity) (anchored 1))

# Extract number or date value from the phrase
(rule $Set ($PHRASE) (NumberFn) (anchored 1))
(rule $Set ($PHRASE) (DateFn) (anchored 1))
(when yearrange
  (rule $Set ($PHRASE) (DateRangeFn) (anchored 1))
)

# Allow |or| on two entities. (Allowing |or| on any Sets leads to massive explosion)
(when alternative
  (rule $Entity ($PHRASE) (FuzzyMatchFn entity) (anchored 1))
  (rule $Set ($Entity $Entity)
    (tables.grow.ApplyFn (lambda e1 (lambda e2 (or (var e1) (var e2)))))
  )
)

################################
# Floating Rules

# Set of all rows
(rule $Set (nothing) (ConstantFn (@type @row)))

(when (or closedclass closedclass-generic)
  # Generate things like "null"
  (rule $Set (nothing) (tables.match.ClosedClassFn generic))
)
(when (or closedclass closedclass-column)
  # If a column contains only a few unique things, generate them
  (rule $Set (nothing) (tables.match.ClosedClassFn column))
)

################################################################
# Binaries

# Table column relations (row <-> cell)
(rule $Binary (nothing) (FuzzyMatchFn any binary))

# Normalization relations (cell <-> primitive)
(when (not prenormalized)
  (for @property (@next @index @p.num @p.date @p.num2)
    (rule $Binary (nothing) (ConstantFn @property))
  )
  (when part
    (rule $Binary (nothing) (ConstantFn @p.part))
  )
)
(when prenormalized
  (for @property (@next @index)
    (rule $Binary (nothing) (ConstantFn @property))
  )
)

# Comparison
(when comparison
  (for @comparison (< > <= >=)
    (rule $Comparison (nothing) (ConstantFn @comparison))
  )
)
(when neq
  (rule $Neq (nothing) (ConstantFn !=))
)

################################################################
# Composition on Sets

################################
# Set = g(Set)

# Joins (apply Binary on Set)
(rule $Set ($Set $Binary) (tables.grow.ApplyFn (lambda s (lambda b ((var b) (var s))))))
(rule $Set ($Set $Binary) (tables.grow.ApplyFn (lambda s (lambda b ((@R (var b)) (var s))))))
(rule $Set ($Set $Comparison) (tables.grow.ApplyFn (lambda s (lambda c ((var c) (var s))))))
(rule $Set ($Set $Neq) (tables.grow.ApplyFn (lambda s (lambda c ((var c) (var s))))))

# Aggregates
(for @aggregate (count min max sum avg)
  (rule $Set ($Set) (tables.grow.ApplyFn (lambda s (@aggregate (var s)))))
)

################################
# Set = g(Set, Set)

# Merge
(when (or merge merge-and)
  (rule $Set ($Set $Set)
        (tables.grow.ApplyFn (lambda s1 (lambda s2 (and (var s1) (var s2))))
                             same-type))
)
(when (or merge merge-or)
  (rule $Set ($Set $Set)
        (tables.grow.ApplyFn (lambda s1 (lambda s2 (or (var s1) (var s2))))
                             same-type))
)

# Arithmetic
(when arithmetic
  (rule $Set ($Set $Set)
        (tables.grow.ApplyFn (lambda s1 (lambda s2 (- (var s1) (var s2))))
                             (arg1-type fb:type.number) (arg2-type fb:type.number)))
)

################################################################
# ScopedFormula

(when scoped

  ################################
  # Map = Grow[start](Set)

  # Set s -> Identity map with domain = s
  (rule $Map ($Set) (tables.grow.BeginGrowFn))

  ################################
  # Map = g(Map)

  # Joins
  (rule $Map ($Map $Binary) (tables.grow.ApplyFn (lambda m (lambda b (lambda x ((var b) ((var m) (var x))))))))
  (rule $Map ($Map $Binary) (tables.grow.ApplyFn (lambda m (lambda b (lambda x ((@R (var b)) ((var m) (var x))))))))
  (rule $Map ($Map $Comparison) (tables.grow.ApplyFn (lambda m (lambda c (lambda x ((var c) ((var m) (var x))))))))

  # Aggregates
  (for @aggregate (count min max sum avg)
    (rule $Map ($Map) (tables.grow.ApplyFn (lambda m (lambda x (@aggregate ((var m) (var x)))))))
  )

  ################################
  # Map = g(Set|Map, Set|Map) with at least 1 Map

  (when (or scoped-2args-merge scoped-2args-merge-and)
    # Need both rules since the children in ingredients are not commutable
    (rule $Map ($Map $Map) (tables.grow.ApplyFn (lambda m1 (lambda m2 (lambda x (and ((var m1) (var x)) ((var m2) (var x))))))
                                                same-type))
    (rule $Map ($Map $Set) (tables.grow.ApplyFn (lambda m1 (lambda s2 (lambda x (and ((var m1) (var x)) (var s2)))))
                                                same-type))
    (rule $Map ($Set $Map) (tables.grow.ApplyFn (lambda s1 (lambda m2 (lambda x (and (var s1) ((var m2) (var x))))))
                                                same-type))
  )
  # This is super productive
  (when (or scoped-2args-merge scoped-2args-merge-or)
    (rule $Map ($Map $Map) (tables.grow.ApplyFn (lambda m1 (lambda m2 (lambda x (or  ((var m1) (var x)) ((var m2) (var x))))))
                                                same-type))
    (rule $Map ($Map $Set) (tables.grow.ApplyFn (lambda m1 (lambda s2 (lambda x (or ((var m1) (var x)) (var s2)))))
                                                same-type))
    (rule $Map ($Set $Map) (tables.grow.ApplyFn (lambda s1 (lambda m2 (lambda x (or  (var s1) ((var m2) (var x))))))
                                                same-type))
  )
  # This is super productive
  (when scoped-2args-arithmetic
    (rule $Map ($Map $Map) (tables.grow.ApplyFn (lambda m1 (lambda m2 (lambda x (- ((var m1) (var x)) ((var m2) (var x))))))
                                                (arg1-type fb:type.number) (arg2-type fb:type.number)))
    (rule $Map ($Map $Set) (tables.grow.ApplyFn (lambda m1 (lambda s2 (lambda x (- ((var m1) (var x)) (var s2)))))
                                                (arg1-type fb:type.number) (arg2-type fb:type.number)))
    (rule $Map ($Set $Map) (tables.grow.ApplyFn (lambda s1 (lambda m2 (lambda x (- (var s1) ((var m2) (var x))))))
                                                (arg1-type fb:type.number) (arg2-type fb:type.number)))
  )

  ################################
  # Set = Grow[end, f](Map)

  # Superlatives
  (rule $Set ($Map) (tables.grow.EndGrowFn (lambda s (lambda r (argmax 1 1 (var s) (reverse (var r)))))))
  (rule $Set ($Map) (tables.grow.EndGrowFn (lambda s (lambda r (argmin 1 1 (var s) (reverse (var r)))))))

  # Set (x in s such that r(x) is nonempty)
  (when set
    (rule $Set ($Map) (tables.grow.EndGrowFn (lambda s (lambda r (and (var s) (mark x (: ((var r) (var x)))))))))
  )

)

################################################################
# ROOT

(rule $ROOT ($Set) (IdentityFn))
