package edu.stanford.nlp.sempre.tables.test; import edu.stanford.nlp.sempre.*; import edu.stanford.nlp.sempre.tables.TableTypeSystem; import fig.basic.LogInfo; public class TableFormulaCanonicalizer { private TableFormulaCanonicalizer() {} public static Formula canonicalizeFormula(Formula formula) { return canonicalizePredicates(Formulas.betaReduction(formula)); } // Canonicalize the following: // * !___ => (reverse ___) except != // * (cell.cell.date (date ___ -1 -1)) => (cell.cell.number (number ___)) // * variable names => x // * (lambda x (relation (var x))) => relation // * (lambda x ((reverse relation) (var x))) => (reverse relation) // * (reverse (lambda x (relation (var x)))) => (reverse relation) // * (reverse (lambda x ((reverse relation) (var x))) => relation // * sort the children of merge formulas static Formula canonicalizePredicates(Formula formula) { if (formula instanceof ValueFormula) { ValueFormula<?> valueF = (ValueFormula<?>) formula; if (valueF.value instanceof NameValue) { String id = ((NameValue) valueF.value).id; if (id.startsWith("!") && !"!=".equals(id)) { return new ReverseFormula(new ValueFormula<Value>(new NameValue(id.substring(1)))); } else { return new ValueFormula<Value>(new NameValue(id)); } } return valueF; } else if (formula instanceof JoinFormula) { JoinFormula join = (JoinFormula) formula; if (join.relation instanceof ValueFormula && join.child instanceof ValueFormula) { Value relation = ((ValueFormula<?>) join.relation).value, child = ((ValueFormula<?>) join.child).value; if (relation.equals(TableTypeSystem.CELL_DATE_VALUE) && child instanceof DateValue) { DateValue date = (DateValue) (((ValueFormula<?>) join.child).value); if (date.month == -1 && date.day == -1) { return new JoinFormula(new ValueFormula<Value>(TableTypeSystem.CELL_NUMBER_VALUE), new ValueFormula<Value>(new NumberValue(date.year))); } } } return new JoinFormula(canonicalizeFormula(join.relation), canonicalizeFormula(join.child)); } else if (formula instanceof MergeFormula) { MergeFormula merge = (MergeFormula) formula; Formula child1 = canonicalizeFormula(merge.child1), child2 = canonicalizeFormula(merge.child2); if (child1.toString().compareTo(child2.toString()) <= 0) return new MergeFormula(merge.mode, child1, child2); else return new MergeFormula(merge.mode, child2, child1); } else if (formula instanceof AggregateFormula) { AggregateFormula aggregate = (AggregateFormula) formula; return new AggregateFormula(aggregate.mode, canonicalizeFormula(aggregate.child)); } else if (formula instanceof SuperlativeFormula) { SuperlativeFormula superlative = (SuperlativeFormula) formula; return new SuperlativeFormula(superlative.mode, superlative.rank, superlative.count, canonicalizeFormula(superlative.head), canonicalizeFormula(superlative.relation)); } else if (formula instanceof ArithmeticFormula) { ArithmeticFormula arithmetic = (ArithmeticFormula) formula; return new ArithmeticFormula(arithmetic.mode, canonicalizeFormula(arithmetic.child1), canonicalizeFormula(arithmetic.child2)); } else if (formula instanceof VariableFormula) { return new VariableFormula("x"); } else if (formula instanceof MarkFormula) { MarkFormula mark = (MarkFormula) formula; return new MarkFormula("x", canonicalizeFormula(mark.body)); } else if (formula instanceof ReverseFormula) { Formula singleRelation; if ((singleRelation = isSingleRelationLambda(formula)) != null) return singleRelation; ReverseFormula reverse = (ReverseFormula) formula; return new ReverseFormula(canonicalizeFormula(reverse.child)); } else if (formula instanceof LambdaFormula) { Formula singleRelation; if ((singleRelation = isSingleRelationLambda(formula)) != null) return singleRelation; LambdaFormula lambda = (LambdaFormula) formula; return new LambdaFormula("x", canonicalizeFormula(lambda.body)); } else { throw new RuntimeException("Unsupported formula " + formula); } } // Detect the following patterns // * (lambda x (relation (var x))) => relation // * (lambda x (!relation (var x))) => (reverse relation) // * (lambda x ((reverse relation) (var x))) => (reverse relation) // * reverse of any case above // Otherwise, return null static Formula isSingleRelationLambda(Formula formula) { boolean isReversed = false; ValueFormula<?> valueF; NameValue relation; // Outer layer if (formula instanceof ReverseFormula) { isReversed = !isReversed; formula = ((ReverseFormula) formula).child; } if (!(formula instanceof LambdaFormula)) return null; formula = ((LambdaFormula) formula).body; if (!(formula instanceof JoinFormula)) return null; JoinFormula join = (JoinFormula) formula; if (!(join.child instanceof VariableFormula)) return null; // Detect relation if (join.relation instanceof ValueFormula) { valueF = (ValueFormula<?>) join.relation; } else if (join.relation instanceof ReverseFormula) { ReverseFormula reverse = (ReverseFormula) join.relation; if (!(reverse.child instanceof ValueFormula)) return null; isReversed = !isReversed; valueF = (ValueFormula<?>) reverse.child; } else { return null; } if (!(valueF.value instanceof NameValue)) return null; relation = (NameValue) valueF.value; if (!CanonicalNames.isBinary(relation)) return null; if (CanonicalNames.isReverseProperty(relation)) { isReversed = !isReversed; relation = CanonicalNames.reverseProperty(relation); } // Return the answer if (isReversed) { return new ReverseFormula(new ValueFormula<NameValue>(relation)); } else { return new ValueFormula<NameValue>(relation); } } // ============================================================ // Test // ============================================================ public static void main(String[] args) { LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(lambda x (fb:a.b.c (var x)))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(lambda x (!fb:a.b.c (var x)))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(lambda x ((reverse fb:a.b.c) (var x)))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(lambda x ((reverse fb:a.b.c) (fb:d.e.f (var x))))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(lambda x (!= (var x)))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(reverse (lambda x (fb:a.b.c (var x))))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(reverse (lambda x (!fb:a.b.c (var x))))"))); LogInfo.logs("%s", isSingleRelationLambda(Formula.fromString("(reverse (lambda x ((reverse fb:a.b.c) (var x))))"))); } }