# (Combined) Generic Grammar
# Use more generic compositional patterns.

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

(def @R reverse)
(def @type fb:type.object.type)
(def @row fb:type.row)

(def @next fb:row.row.next)
(def @!next !fb:row.row.next)
(def @index fb:row.row.index)
(def @!index !fb:row.row.index)

(def @p.num fb:cell.cell.number)
(def @!p.num !fb:cell.cell.number)
(def @p.date fb:cell.cell.date)
(def @!p.date !fb:cell.cell.date)
(def @p.num2 fb:cell.cell.num2)
(def @!p.num2 !fb:cell.cell.num2)

################################################################
# Lexicon

################################
# Anchored Rules: Entity, Unary, Binary
(rule $Entity ($PHRASE) (FuzzyMatchFn entity) (anchored 1))
#(rule $Binary ($PHRASE) (FuzzyMatchFn binary) (anchored 1))
(rule $Entity ($PHRASE) (NumberFn) (anchored 1))
(rule $Entity ($PHRASE) (DateFn) (anchored 1))

################################
# Create binary from thin air
#(rule $Entity (nothing) (ConstantFn fb:cell.null))
(rule $Binary (nothing) (FuzzyMatchFn any binary))
(rule $Unary (nothing) (FuzzyMatchFn any unary))

################################
# Property
# (@p.num (number 42)) / (@p.date (date 2012 12 21))
(for @property (@p.num @p.date)
  (rule $Property (nothing) (ConstantFn @property))
)
(when second
  (rule $Property (nothing) (ConstantFn @p.num2))
)

################################################################
# Composition

# $RowSet = list of rows (type = fb:row.row)
# $ValueSet = list of values (NameValue or other primitives)
# $SingleValue = number representing count (may not make sense to compose it with other things)

################################
# Generic RowSet
# (@type @row)
(rule $RowSet (nothing) (ConstantFn (@type @row)))

################################
# Anchored ValueSet
# c_name.barack_obama
(rule $ValueSet ($Entity) (IdentityFn))

# [TAG] alternative: "X or Y" questions
(when alternative
  # (or c_name.barack_obama c_name.bill_clinton)
  (rule $ValueSet ($Entity $Entity)
    (lambda e1 (lambda e2 (or (var e1) (var e2))))
  )
)

# [TAG] t-alternative
(when t-alternative
  (rule $AnchoredOr ($LEMMA_TOKEN) (FilterTokenFn lemma and or) (anchored 1))
  (rule $ValueSet ($AnchoredOr $Entity $Entity)
    (lambda a (lambda e1 (lambda e2 (or (var e1) (var e2)))))
  )
)

################################
# Join
# (c.name c_name.barack_obama)
(rule $RowSet ($Binary $ValueSet) (lambda b (lambda v ((var b) (var v)))))
# (!c.name (...[rows]...)) --> c_name.barack_obama
(rule $ValueSet ($Binary $RowSet) (lambda b (lambda r ((@R (var b)) (var r)))))
# (c.height (@p.num (number 180)))
(rule $RowSet ($Binary $Property $ValueSet)
  (lambda b (lambda p (lambda v ((var b) ((var p) (var v))))))
)
# (@!p.num (!c.height (...[rows]...))) --> (number 180)
(rule $ValueSet ($Binary $Property $RowSet)
  (lambda b (lambda p (lambda r ((@R (var p)) ((@R (var b)) (var r))))))
)

# [TAG] movement: "next" / "previous"
(when movement
  # (@next (...[rows]...)) --> ...[rows]...
  (for @movement (@next @!next)
    (rule $RowSet ($RowSet) (lambda r (@movement (var r))))
  )
)

# [TAG] t-movement
(when t-movement
  (rule $AnchoredMovement ($LEMMA_TOKEN) (FilterTokenFn lemma next previous after before above below) (anchored 1))
  (for @movement (@next @!next)
    (rule $RowSet ($AnchoredMovement $RowSet) (lambda m (lambda r (@movement (var r)))))
  )
)

# [TAG] comparison: "at least" / "more than"
(when comparison
  # (c.height (@p.num (>= (number 180))))
  (for @comparison (< > <= >=)
    (rule $RowSet ($Binary $Property $Entity)
      (lambda b (lambda p (lambda e ((var b) ((var p) (@comparison (var e)))))))
    )
  )
)

# [TAG] != : "not zero" / "same"
(when neq
  # (c.name (!= c_name.barack_obama))
  (rule $RowSet ($Binary $Entity) (lambda b (lambda e ((var b) (!= (var e))))))
  # (c.height (@p.num (!= (number 180))))
  (rule $RowSet ($Binary $Property $Entity)
    (lambda b (lambda p (lambda e ((var b) ((var p) (!= (var e)))))))
  )
)

# [TAG] t-comparison
(when t-comparison
  (rule $AnchoredMore ($LEMMA_TOKEN) (FilterTokenFn lemma more than least above after) (anchored 1))
  (for @comparison (> >=)
    (rule $RowSet ($AnchoredMore $Binary $Property $Entity)
      (lambda a (lambda b (lambda p (lambda e ((var b) ((var p) (@comparison (var e))))))))
    )
  )
  (rule $AnchoredLess ($LEMMA_TOKEN) (FilterTokenFn lemma less than most below before) (anchored 1))
  (for @comparison (< <=)
    (rule $RowSet ($AnchoredLess $Binary $Property $Entity)
      (lambda a (lambda b (lambda p (lambda e ((var b) ((var p) (@comparison (var e))))))))
    )
  )
)

################################
# Aggregate

# [TAG] count
# (count (...[rows]...)) --> (number 4)
(when count
  (rule $SingleValue ($RowSet) (lambda r (count (var r))))
)

# [TAG] t-count
(when t-count
  (rule $AnchoredCount ($LEMMA_TOKEN) (FilterTokenFn lemma how many total number) (anchored 1))
  (rule $SingleValue ($AnchoredCount $RowSet) (lambda a (lambda r (count (var r)))))
)

# [TAG] aggregate: "sum" / "average" / "maximum"
# (max (...[rows]...)) --> (number 42)
(when aggregate
  (rule $SingleValue ($ValueSet) (lambda r (min (var r))))
  (rule $SingleValue ($ValueSet) (lambda r (max (var r))))
  (rule $SingleValue ($ValueSet) (lambda r (sum (var r))))
  (rule $SingleValue ($ValueSet) (lambda r (avg (var r))))
)

# [TAG] t-aggregate
(when t-aggregate
  (rule $AnchoredSum ($LEMMA_TOKEN) (FilterTokenFn lemma all combine total) (anchored 1))
  (rule $SingleValue ($AnchoredSum $ValueSet) (lambda a (lambda r (sum (var r)))))
  (rule $AnchoredAvg ($LEMMA_TOKEN) (FilterTokenFn lemma average) (anchored 1))
  (rule $SingleValue ($AnchoredAvg $ValueSet) (lambda a (lambda r (avg (var r)))))
)

################################
# Functions (used in superlative and arithmetic)

# Function on row set -- used in:
# (argmax 1 1 (@type @row) (reverse ___))
# ___ = (lambda r (@!p.num (!c.height (var r))))
# "highest"
(rule $FnOnRow ($Binary $Property)
  (lambda b (lambda p (lambda r ((@R (var p)) ((@R (var b)) (var r))))))
)

# Function on value set -- used in:
# (argmax 1 1 (!c.name (@type @row)) (reverse ___))
# ___ = (lambda v (@!p.num (!c.height (c.name (var v)))))
# "which person is the highest"
(rule $FnOnValue ($Binary $Binary $Property)
  (lambda b1 (lambda b2 (lambda p (lambda v ((@R (var p)) ((@R (var b2)) ((var b1) (var v))))))))
)

(when count
  # (argmax 1 1 (!c.name (@type @row)) (reverse ___))
  # ___ = (lambda v (count (c.name (var v))))
  # "which name occurs the most often" / "who won the most awards"
  (rule $FnOnValue ($Binary)
    (lambda b (lambda v (count ((var b) (var v)))))
  )
  # (argmax 1 1 (@!p.num (!c.height (@type @row))) (reverse ___))
  # ___ = (lambda v (count (c.height (@p.num (var v)))))
  # "which height occurs the most often"
  (rule $FnOnValue ($Binary $Property)
    (lambda b (lambda p (lambda v (count ((var b) ((var p) (var v)))))))
  )
)

(when t-count
  (rule $FnOnValue ($AnchoredCount $Binary)
    (lambda t (lambda b (lambda v (count ((var b) (var v))))))
  )
  (rule $FnOnValue ($AnchoredCount $Binary $Property)
    (lambda t (lambda b (lambda p (lambda v (count ((var b) ((var p) (var v))))))))
  )
)

################################
# Superlative

# [TAG] superlative: "first", "last", "biggest", "lowest"
(when superlative
  (for @argm (argmax argmin)
    # "first", "last"
    (rule $RowSet ($RowSet) (lambda r (@argm 1 1 (var r) @index)))
    # Generic argmax / argmin on rows or values
    (rule $RowSet ($RowSet $FnOnRow) (lambda r (lambda f (@argm 1 1 (var r) (@R (var f))))))
    (when u-superlative
      (rule $ValueSet ($Unary $FnOnValue) (lambda u (lambda f (@argm 1 1 (var u) (reverse (var f))))))
      (rule $ValueSet ($Entity $Entity $FnOnValue)
        (lambda e1 (lambda e2 (lambda f (@argm 1 1 (or (var e1) (var e2)) (reverse (var f))))))
      )
    )
    (when v-superlative
      (rule $ValueSet ($ValueSet $FnOnValue) (lambda v (lambda f (@argm 1 1 (var v) (reverse (var f))))))
    )
  )
)

# [TAG] t-superlative: only trigger superlatives on appropriate anchors
(when t-superlative
  # Anchors
  (rule $SuperlativeTrigger ($LEMMA_TOKEN) (FilterPosTagFn token JJR JJS RBR RBS) (anchored 1))
  (rule $SuperlativeTrigger ($LEMMA_TOKEN) (FilterTokenFn lemma top first bottom last) (anchored 1))
  # Superlatives
  (for @argm (argmax argmin)
    (rule $RowSet ($SuperlativeTrigger $RowSet) (lambda t (lambda r (@argm 1 1 (var r) @index))))
    # Generic argmax / argmin on rows or values
    (rule $RowSet ($SuperlativeTrigger $RowSet $FnOnRow) (lambda t (lambda r (lambda f (@argm 1 1 (var r) (@R (var f)))))))
    (when u-superlative
      (rule $ValueSet ($SuperlativeTrigger $Unary $FnOnValue) (lambda t (lambda u (lambda f (@argm 1 1 (var u) (reverse (var f)))))))
      (rule $ValueSet ($SuperlativeTrigger $Entity $Entity $FnOnValue)
        (lambda t (lambda e1 (lambda e2 (lambda f (@argm 1 1 (or (var e1) (var e2)) (reverse (var f)))))))
      )
    )
    (when v-superlative
      (rule $ValueSet ($SuperlativeTrigger $ValueSet $FnOnValue) (lambda t (lambda v (lambda f (@argm 1 1 (var v) (@R (var f)))))))
    )
  )
)

################################
# Arithmetic

# [TAG] arithmetic: "How much taller is Barack Obama than Bill Clinton"
# (- (... (c_name.barack_obama)) (... (c_name.bill_clinton)))
(when arithmetic
  (rule $SingleValue ($FnOnValue $Entity $Entity)
    (lambda f (lambda e1 (lambda e2 (- ((var f) (var e1)) ((var f) (var e2))))))
  )
)

# [TAG] t-arithmetic
(when t-arithmetic
  (rule $AnchoredSub ($LEMMA_TOKEN) (FilterTokenFn lemma difference between and much) (anchored 1))
  (rule $SingleValue ($AnchoredSub $FnOnValue $Entity $Entity)
    (lambda a (lambda f (lambda e1 (lambda e2 (- ((var f) (var e1)) ((var f) (var e2)))))))
  )
)

################################
# Merge

# [TAG] merge: "bigger than 10 and is from Russia"
# Warning: Without pruning, this can blow up the search space!
(when merge
  (rule $RowSet ($RowSet $RowSet)
    (lambda r1 (lambda r2 (and (var r1) (var r2))))
  )
)

################################
# ROOT
(rule $ROOT ($ValueSet) (IdentityFn))
(rule $ROOT ($SingleValue) (IdentityFn))

################################################################
# For debugging:

(when debug 
  (rule $Any ($ValueSet) (IdentityFn))
  (rule $Any ($RowSet) (IdentityFn))
  (rule $Any ($SingleValue) (IdentityFn))
  (rule $ROOT ($Any) (IdentityFn))
)
