Search in sources :

Example 6 with Theory

use of com.sri.ai.grinder.sgdpllt.api.Theory in project aic-expresso by aic-sri-international.

the class ExpressoAPIExamples method main.

public static void main(String[] args) {
    // Symbols are expressions representing Java values, such as a string,
    // a number, a boolean, and even any other objects (Expressions themselves will throw an error, though, to prevent common mistakes)
    Expression a = DefaultSymbol.createSymbol("a");
    Expression ten = DefaultSymbol.createSymbol(10);
    Expression trueValue = DefaultSymbol.createSymbol(true);
    Expression object = DefaultSymbol.createSymbol(Car.ferrari);
    // Below, we use Util.println to avoid having to write System.out.println.
    // Util has lots and lots and lots of very useful methods that eliminate boring Java chores.
    // We definitely recommend studying it carefully!
    // To easily write just "println" and have it work, write "println" and use Ctrl-1 to be offered the option
    // of statically importing Util.println.
    // You can statically import an identifier in Eclipse by placing the cursor on it and pressing Shift-Ctrl-M in Windows.
    println("a        : " + a);
    println("ten      : " + ten);
    println("trueValue: " + trueValue);
    println("object   : " + object);
    // It is easier to remember to make symbols using Expressions.makeSymbol:
    // 'Expressions' is a class with lots of useful static methods for working with expressions.
    // This of it as the counterpart of 'Util', but for expressions.
    // Having many useful expression classes in a single place makes it easier to remember them and access them through code completion.
    // As with 'Util', we often import its methods statically.
    a = makeSymbol("a");
    ten = makeSymbol(10);
    trueValue = makeSymbol(true);
    object = makeSymbol(Car.ferrari);
    println("a        : " + a);
    println("ten      : " + ten);
    println("trueValue: " + trueValue);
    println("object   : " + object);
    // The second most important type of expressions are function applications.
    // They consist of a functor (an expression representing a function, typically a symbol) applied to zero or more arguments:
    Expression f = makeSymbol("f");
    Expression g = makeSymbol("g");
    Expression fATen = new DefaultFunctionApplication(f, list(a, ten));
    Expression gOnNothing = new DefaultFunctionApplication(g, list());
    println("function f applied to a and ten: " + fATen);
    println("function g applied to nothing: " + gOnNothing);
    // It is much easier to use Expressions.apply:
    fATen = apply(f, a, ten);
    gOnNothing = apply(g);
    println("function f applied to a and ten: " + fATen);
    println("function g applied to nothing: " + gOnNothing);
    // Naturally, function applications can be applied to any expression, including other function applications:
    Expression gFATen = apply(g, apply(f, a, ten));
    println("function g applied to function f applied to a and ten: " + gFATen);
    // If we do not create symbols for Java values, apply does it automatically for us:
    gFATen = apply("g", apply("f", "a", 10));
    println("function g applied to function f applied to a and ten: " + gFATen);
    // Some operators are output in special infix notation for readability:
    // again not creating symbols first
    Expression twoPlusTwoPlusThree = apply("+", 2, 2, 3);
    println("two plus two plus three: " + twoPlusTwoPlusThree);
    Expression arithmetic1 = apply("*", 2, apply("+", 2, 3));
    Expression arithmetic2 = apply("+", 2, apply("*", 2, 3));
    println("Arithmetic gets printed while respecting usual precedence rules by using parentheses: " + arithmetic1);
    println("Arithmetic gets printed while respecting usual precedence rules by using parentheses: " + arithmetic2);
    // Same for logic:
    Expression logic1 = apply("and", "p", apply("or", "q", "r"));
    Expression logic2 = apply("or", "p", apply("and", "q", "r"));
    println("Same for logic: " + logic1);
    println("Same for logic: " + logic2);
    // It is not good practice to use separate strings for referring to the same operators.
    // In the future, we may decide to change the string associated to an operator
    // and have that string used in many places would make that hard to effect.
    // FunctorConstants is a class with lots of static fields for operator strings:
    arithmetic1 = apply(FunctorConstants.TIMES, 2, apply(FunctorConstants.PLUS, 2, 3));
    logic1 = apply(FunctorConstants.AND, "p", apply(FunctorConstants.OR, "q", "r"));
    // Functor constants can also be statically imported:
    arithmetic1 = apply(TIMES, 2, apply(PLUS, 2, 3));
    logic1 = apply(AND, "p", apply(OR, "q", "r"));
    // We can access the functor and arguments of a function application:
    println("The functor of " + gFATen + " is " + gFATen.getFunctor());
    println("The second argument of " + fATen + " is " + fATen.get(1));
    // returns a List<Expression>
    println("All arguments of " + fATen + " are " + fATen.getArguments());
    // We can also set new functors or arguments.
    // IMPORTANT: expressions are IMMUTABLE, so this creates a new expression,
    // although it does re-use the unchanged parts.
    Expression newArgument = gFATen.set(0, a);
    println("Changed first argument of " + gFATen + " to " + a + " and obtained " + newArgument);
    println("Original expression continues the same, since they are immutable: " + gFATen);
    // getFunctor returns a symbol, so to check if it is, for example, "f", we need
    // to write expression.getFunctor().equals(makeSymbol("f"))
    // which is too long.
    // Instead, we can use 'hasFunctor'
    println(fATen + " has functor \"f\": " + fATen.hasFunctor("f"));
    // Finally, we can parse expressions for strings.
    // BUT we should never use that to construct expressions if we have the sub-expressions already represented as Java objects.
    // For example, don't do this: parse("f(" + a + ", " + b + ")");
    // Instead, use apply("f", a, b);
    ten = parse("10");
    trueValue = parse("true");
    fATen = parse("f(a,10)");
    arithmetic1 = parse("2*(2 + 3)");
    arithmetic2 = parse("2+(2 * 3)");
    println(ten);
    println(trueValue);
    println(fATen);
    println(arithmetic1);
    println(arithmetic2);
    // Another important type of expression is sets.
    // There are two dimensions for sets: they can be uni- or multi-sets, and they can be extensionally or intensionally defined.
    //
    // A uni-set has at most one instance of each element in it. This is the typical mathematical set.
    // A multi-set may have multiple instances of the same element in it.
    // For example, the multi-set {1,2,2,3} is distinct from multi-set {1,2,2,2,3}.
    // In Expresso, we use double-brackets for denoting multi-sets:  {{ 1, 2, 2, 3 }}.
    // {{ }} denotes the empty multi-set.
    // The singleton uni-set with an empty set in it is denoted { {} }.
    // You need a space between the brackets to avoid them being parsed as a double bracket.
    //
    // An extensionally defined set is an explicit enumeration of its elements: {1, 2, 3}, {{1, 2, 2, 3}}, {}, {{ }}.
    // An intensionally defined set is defined by a condition: { (on I in Integer)  I^2 : I > 3 and I <= 100 }, for example,
    // which is equal to { 16, 25, 36, ..., 10000 }.
    // The general form of an intensionally defined set (or, less precisely but more succinctly, an intensional set) is
    // { (on Index1 in Index1Domain, Index2 in Index2Domain, ..., Index_n in Index_nDomain)   Head   :  Condition }
    // We can also have intensionally defined multi-sets using double brackets.
    // Here are some ways of constructing sets:
    a = makeSymbol("a");
    Expression b = makeSymbol("b");
    Expression c = makeSymbol("c");
    Expression d = makeSymbol("d");
    Expression extensionalUniSet = ExtensionalSets.makeUniSet(a, b, c, d);
    Expression extensionalMultiSet = ExtensionalSets.makeMultiSet(a, b, c, d);
    println(extensionalUniSet);
    println(extensionalMultiSet);
    // Creating an intensionally defined set programmatically (as opposed to parsing a string description of it)
    // is a bit of work (this will be shown below).
    // Here's an example of parsing one:
    Expression intensionalUniSet = parse("{ ( on P in People, F in Foods ) eats(P, F) : not (P = Rodrigo and F = shrimp) }");
    println(intensionalUniSet);
    // Here's how to do it from scratch, but see next the way we typically actually do it.
    Expression p = makeSymbol("P");
    Expression people = makeSymbol("People");
    f = makeSymbol("F");
    Expression foods = makeSymbol("Foods");
    IndexExpressionsSet indices = new ExtensionalIndexExpressionsSet(apply(IN, p, people), apply(IN, f, foods));
    // The "extensional" in ExtensionalIndexExpressionsSet means that the list/set of indices is extensionally defined,
    // even though they will be the indices of an intensionally defined set.
    intensionalUniSet = // IntensionalSet.intensionalUniSet, or simply intensionalUniSet, also works
    IntensionalSet.makeUniSet(indices, apply("eats", p, f), apply(NOT, apply(AND, Equality.make(p, "Rodrigo"), Equality.make(f, "shrimp"))));
    // Note that Equality.make(p, "Rodrigo") is the same as apply(FunctorConstants.EQUAL, p, "Rodrigo").
    // We often have 'make' methods for many operators: And.make, Or.make and so on.
    // packages in com.sri.ai.expresso.grinder.sgdpllt.library have many such operator-specific classes.
    println(intensionalUniSet);
    // When writing code on sets, we typically are modifying an existing set expression, so we can re-use its parts,
    // by using special part-replacement methods.
    // This requires the variable to implement the IntensionalSet interface, though.
    // IMPORTANT: expressions are IMMUTABLE, so setCondition and other part-replacement methods return a NEW expression,
    // although the parts not replaced are re-used.
    IntensionalSet intensionalSetCast = (IntensionalSet) intensionalUniSet;
    Expression noCondition = intensionalSetCast.setCondition(makeSymbol(true));
    println("Set with no condition: " + noCondition);
    Expression headSaysLoveInsteadOfEats = intensionalSetCast.setHead(apply("loves", p, f));
    println("Set with new head: " + headSaysLoveInsteadOfEats);
    Expression withNewIndices = intensionalSetCast.setIndexExpressions(new ExtensionalIndexExpressionsSet(apply(IN, p, people), apply(IN, f, foods), apply(IN, "D", "Days")));
    println("Set with new indices: " + withNewIndices);
    // summations and products are just function applications of FunctorConstants.SUM and FunctorConstants.PRODUCT on intensional multi-sets.
    // sum( {{ (on Indices)  Head  : Condition }} ) represents the summation (in Latex notation) sum_{Indices : Condition} Head
    Expression summation = apply(SUM, intensionalSetCast);
    println(summation);
    Expression product = apply(PRODUCT, intensionalSetCast);
    println(product);
    ///// Evaluating expressions
    // The above code shows how to deal with the syntax of expressions.
    // Evaluating expressions requires knowing about the semantics, that is, to what functions each operator corresponds to ("+" to addition, etc).
    // This is provided by a theory, which for now it suffices to know is a collection of methods for evaluating expressions
    // according to an interpretation to some symbols.
    Theory theory = new CompoundTheory(new EqualityTheory(false, true), new DifferenceArithmeticTheory(false, false), new LinearRealArithmeticTheory(false, false), new TupleTheory(), new PropositionalTheory());
    // Because this evaluation is symbolic, evaluated expressions may involve free variables.
    // In this case, the result of the evaluation will be a simplified expression that
    // is equivalent to the original expression for all possible assignments to the free variables.
    // For example, X + 0*Y is evaluate to X because, for any assignment to (X,Y), X + 0*Y = X.
    // true context: all assignments to free variables are of interest
    Context context = new TrueContext(theory);
    // We will later see how we can use contexts that restrict the free variable assignments of interest.
    // Now that we have a theory and a context, we can evaluate expressions:
    println("1 + 0*X + 1  =  " + theory.evaluate(parse("1 + 1"), context));
    evaluate(new String[] { "1 + 1", "2", "X + 1 + 1", "X + 2", "sum({{ (on I in 1..10) I }})", "55", "product({{ (on I in 1..5) 2 : I != 3 and I != 5 }})", "8" }, theory, context);
    // now let us assume we have a free variable J which is an integer
    // Contexts are, like expressions, also IMMUTABLE:
    Context context2 = context.extendWithSymbolsAndTypes("J", "Integer");
    // However, here we just want to use the same variable 'context' all along, so we keep the updated context in it:
    context = context2;
    // Because we store the reference to the modified context in the same variable, we lose the reference to the original one,
    // but, if we wanted, we could keep contexts in a stack, for example,
    // so that we could always easily revert back to a previous context if needed.
    evaluate(new String[] { "X + 1 + 1 + J", "X + 2 + J", "sum({{ (on I in 1..10) I : I != J }})", "if J > 0 then if J <= 10 then -1 * J + 55 else 55 else 55" }, theory, context);
    // now let us assume we have a free variable J which is an integer
    // The context is also a boolean formula (a constraint)
    // Current, its value is "true", but we can conjoin it with a literal J < 0
    context = context.conjoin(parse("J < 0"));
    evaluate(new String[] { "J < 1", "true", // J is irrelevant because it is out of the range of I
    "sum({{ (on I in 1..1000) I : I != J }})", // J is irrelevant because it is out of the range of I
    "500500" }, theory, context);
    // we now add another symbol and constraint
    context = context.extendWithSymbolsAndTypes("K", "Integer");
    context = context.conjoin(parse("K > 0"));
    evaluate(new String[] { "J < K", "true" }, theory, context);
    // Obtaining all free variables in an expression.
    // In order to obtain all free variables appearing in an expression
    // (and therefore excluding quantified variables (for all X, there exists X) and set indices ({ (on Z in Real) Z }))
    // we must traverse the expression and select its sub-expressions that are variables.
    // However, we need to know what a variable is.
    // It is not enough to say that any symbol is a variable, because "1" and "true" are symbols, but not variables.
    // It is not enough to say that any symbols that is an identifier (starting with an alphabet letter) is a variable,
    // because we may have uniquely named constants such as "john" and "bob" that are not to be treated as variables
    // (we want "john = bob" to be evaluated to "false", and if they were variable, this would not happen.
    // The way Expresso deals with this question is by letting the user define a predicate in the context that
    // encoded what a uniquely named constant is, and considering any other symbol to be considered a variable.
    // By default, Expresso follows the Prolog convention of capitalized variables: X is a variable, x is not.
    // Note how this takes "Real" to be a variable!
    context = new TrueContext();
    Expression expression = parse("X + f(g(x, Y, 1, true, false, 10, bob, john, there exists Z in Real : 10, { (on W in Real) 1 } ))");
    Set<Expression> variablesInExpression = Expressions.freeVariables(expression, context);
    // outputs [X, Y]
    println("variables in " + expression + " by Prolog standard: " + variablesInExpression);
    // More recently, we have adopted the practice of not caring about capitalization.
    // This means that we may, for example, defined uniquely named constants to be any symbols that are not in a given set of variables.
    Set<Expression> allVariables = set(parse("x"), parse("X"), parse("Y"), parse("Z"), parse("W"));
    context = context.setIsUniquelyNamedConstantPredicate(new UniquelyNamedConstantAreAllSymbolsNotIn(allVariables));
    variablesInExpression = Expressions.freeVariables(expression, context);
    println("variables in " + expression + " if all variables is " + allVariables + ": " + // outputs [x, X, Y]
    variablesInExpression);
    // Sometimes, it is useful to replace subexpressions in a given expression by another subexpression:
    expression = parse("f(f(f(X))) + X");
    Expression valueOfX = parse("10");
    Expression replacementOfFirstOccurrenceOnly = expression.replaceFirstOccurrence(parse("X"), valueOfX, context);
    println("Replacing only the first occurrence of X by its value gives " + replacementOfFirstOccurrenceOnly);
    Expression replacementOfAllOccurrences = expression.replaceAllOccurrences(parse("X"), valueOfX, context);
    println("Replacing all occurrences of X by its value gives " + replacementOfAllOccurrences);
    // There are a LOT of variants of these functions in Expression (not Expressions),
    // including some very flexible ones that allow the user to provide a function for determining the replacement.
    // BUG: need to debug
    // Here's how to decide if a point is in the convex hull of other two points:
    Context convexityContext = context.extendWithSymbolsAndTypes("p", "Real", "p1", "Real", "p2", "Real");
    //convexityContext = convexityContext.conjoin(parse("p  = 4"));
    //convexityContext = convexityContext.conjoin(parse("p1 = 3"));
    //convexityContext = convexityContext.conjoin(parse("p2 = 5"));
    Expression isInConvexHull = parse("there exists c1 in Real : there exists c2 in Real : " + "0 <= c1 and c1 <= 1 and 0 <= c2 and c2 <= 1 and 4 = c1*3 + c2*5");
    Expression result = theory.evaluate(isInConvexHull, convexityContext);
    println("4 is in the convex hull of 3 and 5: " + result);
}
Also used : Context(com.sri.ai.grinder.sgdpllt.api.Context) TrueContext(com.sri.ai.grinder.sgdpllt.core.TrueContext) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) LinearRealArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.linearrealarithmetic.LinearRealArithmeticTheory) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) TupleTheory(com.sri.ai.grinder.sgdpllt.theory.tuple.TupleTheory) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) LinearRealArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.linearrealarithmetic.LinearRealArithmeticTheory) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) TupleTheory(com.sri.ai.grinder.sgdpllt.theory.tuple.TupleTheory) TrueContext(com.sri.ai.grinder.sgdpllt.core.TrueContext) ExtensionalIndexExpressionsSet(com.sri.ai.expresso.core.ExtensionalIndexExpressionsSet) IntensionalSet(com.sri.ai.expresso.api.IntensionalSet) UniquelyNamedConstantAreAllSymbolsNotIn(com.sri.ai.grinder.helper.UniquelyNamedConstantAreAllSymbolsNotIn) Expression(com.sri.ai.expresso.api.Expression) DefaultFunctionApplication(com.sri.ai.expresso.core.DefaultFunctionApplication) ExtensionalIndexExpressionsSet(com.sri.ai.expresso.core.ExtensionalIndexExpressionsSet) IndexExpressionsSet(com.sri.ai.expresso.api.IndexExpressionsSet)

Example 7 with Theory

use of com.sri.ai.grinder.sgdpllt.api.Theory in project aic-expresso by aic-sri-international.

the class SymbolicShell method main.

public static void main(String[] args) {
    CompoundTheory theory = new CompoundTheory(new EqualityTheory(false, true), new DifferenceArithmeticTheory(false, false), new LinearRealArithmeticTheory(false, false), new TupleTheory(), new PropositionalTheory());
    Context context = new TrueContext(theory);
    context = context.add(BOOLEAN_TYPE);
    context = context.add(new Categorical("People", 1000000, makeSymbol("ann"), makeSymbol("bob"), makeSymbol("ciaran")));
    context = context.add(new IntegerInterval("Integer"));
    context = context.add(new RealInterval("Real"));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("P"), makeSymbol("Boolean")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("Q"), makeSymbol("Boolean")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("R"), makeSymbol("Boolean")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("S"), makeSymbol("Boolean")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("C"), makeSymbol("People")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("D"), makeSymbol("People")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("E"), makeSymbol("People")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("I"), makeSymbol("Integer")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("J"), makeSymbol("Integer")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("K"), makeSymbol("Integer")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("X"), makeSymbol("Real")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("Y"), makeSymbol("Real")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("Z"), makeSymbol("Real")));
    context = context.registerAdditionalSymbolsAndTypes(map(makeSymbol("T"), parse("(1..5 x 1..5)")));
    ConsoleIterator consoleIterator = getConsole(args);
    help(consoleIterator);
    Collection<String> examples = list("sum({{ (on C in People)  3 }})", "sum({{ (on C in People)  3 :  C != D }})", "product({{ (on C in People)  3 :  C != D }})", "| {{ (on C in People)  3 :  C != D }} |", "| { (on C in People)  tuple(C) :  C != D } |", "max({{ (on C in People)  3 :  C != D }})", "sum({{ (on C in People, D in People)  3 :  C != D }})", "sum({{ (on C in People)  3 :  C != D and C != ann }})", "sum({{ (on C in People, P in Boolean)  3 :  C != ann }})", "sum({{ (on C in People, P in Boolean)  3 :  C != ann and not P }})", "sum({{ (on C in People, D in People)  if C = ann and D != bob then 2 else 0  :  for all E in People : E = ann => C = E }})", "sum({{ (on I in 1..100)  I }})", "sum({{ (on I in 1..100)  I : I != 3 and I != 5 and I != 500 }})", "sum({{ (on I in 1..100)  I : I != J and I != 5 and I != 500 }})", "sum({{ (on I in 1..100)  (I - J)^2 }})", "sum({{ (on I in 1..100)  if I != K then (I - J)^2 else 0 }})", "sum({{ (on I in 1..100)  I : I >= 3 and I < 21 }})", "sum({{ (on I in 1..100)  I : I > J and I < 5 and I < 500 }})", "sum({{ (on I in 1..100)  (I - J)^2 : I < 50 }})", "sum({{ (on X in [0;100])  1 }})", "sum({{ (on X in [0;100[)  1 }})", "sum({{ (on X in ]0;100])  1 }})", "sum({{ (on X in [0;100])  Y }})", "sum({{ (on X in [0;100])  X }})", "sum({{ (on X in [0;100])  X^2 }})", "sum({{ (on X in [0;100])  X + Y }})", "sum({{ (on X in [0;100])  1 : Y < X and X < Z}})", "sum({{ (on X in Real)  1 : 0 <= X and X <= 100 and Y < X and X < Z}})", "for all X in Real : X > 0 or X <= 0", "for all X in ]0;10] : X > 0", "for all X in [0;10] : X > 0", "| X in 1..10 : X < 4 or X > 8 |", "| X in 1..10, Y in 3..5 : (X < 4 or X > 8) and Y != 5 |", "sum( {{ (on T in (1..4 x 1..4)) 10 }})", "sum( {{ (on T in (1..4 x 1..4)) 10 : T != (2, 3) }})", "sum( {{ (on T in (1..4 x 1..4)) 10 : T != (I, J) }})", "sum( {{ (on T in (1..4 x 1..4)) 10 : get(T, 1) != 2 }})");
    for (String example : examples) {
        consoleIterator.getOutputWriter().println(consoleIterator.getPrompt() + example);
        interpretedInputParsedAsExpression(consoleIterator, theory, example, context);
        consoleIterator.getOutputWriter().println("\n");
    }
    while (consoleIterator.hasNext()) {
        String input = consoleIterator.next();
        if (input.equals("")) {
            consoleIterator.getOutputWriter().println();
        } else if (input.startsWith("show")) {
            consoleIterator.getOutputWriter().println("\n" + join(mapIntoList(context.getSymbolsAndTypes().entrySet(), e -> e.getKey() + ": " + e.getValue()), ", ") + "\n");
        } else if (input.equals("debug")) {
            debug = !debug;
            consoleIterator.getOutputWriter().println("\nDebug toggled to " + debug + "\n");
        } else if (input.equals("help")) {
            help(consoleIterator);
        } else {
            context = interpretedInputParsedAsExpression(consoleIterator, theory, input, context);
        }
    }
    consoleIterator.getOutputWriter().println("\nGoodbye.");
}
Also used : Context(com.sri.ai.grinder.sgdpllt.api.Context) TrueContext(com.sri.ai.grinder.sgdpllt.core.TrueContext) Arrays(java.util.Arrays) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) Categorical(com.sri.ai.expresso.type.Categorical) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) Expression(com.sri.ai.expresso.api.Expression) IntegerInterval(com.sri.ai.expresso.type.IntegerInterval) Util.map(com.sri.ai.util.Util.map) BOOLEAN_TYPE(com.sri.ai.grinder.helper.GrinderUtil.BOOLEAN_TYPE) Expressions.parse(com.sri.ai.expresso.helper.Expressions.parse) OptionParser(joptsimple.OptionParser) GUIConsoleIterator(com.sri.ai.util.console.gui.GUIConsoleIterator) OptionSet(joptsimple.OptionSet) ConsoleIterator(com.sri.ai.util.console.ConsoleIterator) OptionSpec(joptsimple.OptionSpec) Util.join(com.sri.ai.util.Util.join) Collection(java.util.Collection) Util.list(com.sri.ai.util.Util.list) RealInterval(com.sri.ai.expresso.type.RealInterval) Util.mapIntoList(com.sri.ai.util.Util.mapIntoList) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) Context(com.sri.ai.grinder.sgdpllt.api.Context) LinearRealArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.linearrealarithmetic.LinearRealArithmeticTheory) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) Beta(com.google.common.annotations.Beta) List(java.util.List) TrueContext(com.sri.ai.grinder.sgdpllt.core.TrueContext) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) Expressions.makeSymbol(com.sri.ai.expresso.helper.Expressions.makeSymbol) DefaultConsoleIterator(com.sri.ai.util.console.DefaultConsoleIterator) TupleTheory(com.sri.ai.grinder.sgdpllt.theory.tuple.TupleTheory) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) IntegerInterval(com.sri.ai.expresso.type.IntegerInterval) LinearRealArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.linearrealarithmetic.LinearRealArithmeticTheory) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) GUIConsoleIterator(com.sri.ai.util.console.gui.GUIConsoleIterator) ConsoleIterator(com.sri.ai.util.console.ConsoleIterator) DefaultConsoleIterator(com.sri.ai.util.console.DefaultConsoleIterator) Categorical(com.sri.ai.expresso.type.Categorical) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) TupleTheory(com.sri.ai.grinder.sgdpllt.theory.tuple.TupleTheory) TrueContext(com.sri.ai.grinder.sgdpllt.core.TrueContext) RealInterval(com.sri.ai.expresso.type.RealInterval)

Example 8 with Theory

use of com.sri.ai.grinder.sgdpllt.api.Theory in project aic-expresso by aic-sri-international.

the class SGDPLLTTester method runGroupProblemSolvingTestGivenConstraintAndProblem.

/**
	 * @param problem
	 * @param indices
	 * @param constraint
	 * @param body
	 * @param testAgainstBruteForce
	 * @param theoryTestingSupport
	 * @param context
	 * @throws Error
	 */
public static void runGroupProblemSolvingTestGivenConstraintAndProblem(Expression problem, Collection<Expression> indices, Constraint constraint, Expression body, boolean testAgainstBruteForce, TheoryTestingSupport theoryTestingSupport, Context context) throws Error {
    Theory theory = theoryTestingSupport.getTheory();
    Collection<Expression> freeVariables = getFreeVariableMinusIndices(indices, constraint, body, context);
    String problemDescription = problem.toString();
    output(problemDescription);
    Simplifier symbolicInterpreter = (e, c) -> theory.evaluate(e, c);
    long start = System.currentTimeMillis();
    Expression symbolicSolution = symbolicInterpreter.apply(problem, context);
    long time = System.currentTimeMillis() - start;
    output("Symbolic solution: " + symbolicSolution);
    output("Computed in " + time + " ms");
    if (Util.thereExists(new SubExpressionsDepthFirstIterator(symbolicSolution), e -> e instanceof QuantifiedExpression || Sets.isIntensionalSet(e))) {
        throw new Error("Symbolic solution is not quantifier-free: " + symbolicSolution);
    }
    if (testAgainstBruteForce) {
        BinaryFunction<BruteForceCommonInterpreter, Context, Expression> bruteForceSolutionGivenInterpreterAndContextWithAssignmentToOtherVariables = (i, c) -> i.apply(problem, c);
        testSymbolicVsBruteForceComputationForEachAssignment(theory, problemDescription, freeVariables, symbolicSolution, bruteForceSolutionGivenInterpreterAndContextWithAssignmentToOtherVariables, context);
    // A more elegant approach would be to create a "for all free variables : symbolic = problem" expression
    // and solve it by brute force instead of using testSymbolicVsBruteForceComputation
    // which replicates the brute force interpreter to some extent.
    // The reason we do not do this is simply due to the fact that the brute force interpreter would return "false"
    // in case of failure, without indicating which assignment failed, which is very useful for debugging.
    // If interpreters, and in fact the whole framework, provided proofs of its calculations,
    // then we could simply use the more elegant approach.
    } else {
        output("Skipping test againt brute-force.");
    }
}
Also used : BinaryFunction(com.sri.ai.util.base.BinaryFunction) Util.removeFromSetNonDestructively(com.sri.ai.util.Util.removeFromSetNonDestructively) SubExpressionsDepthFirstIterator(com.sri.ai.expresso.helper.SubExpressionsDepthFirstIterator) Expression(com.sri.ai.expresso.api.Expression) Constraint(com.sri.ai.grinder.sgdpllt.api.Constraint) Function(java.util.function.Function) GrinderUtil(com.sri.ai.grinder.helper.GrinderUtil) Util.in(com.sri.ai.util.Util.in) ThereExists(com.sri.ai.grinder.sgdpllt.library.boole.ThereExists) AbstractIterativeMultiIndexQuantifierElimination(com.sri.ai.grinder.sgdpllt.interpreter.AbstractIterativeMultiIndexQuantifierElimination) Expressions.parse(com.sri.ai.expresso.helper.Expressions.parse) Map(java.util.Map) CompleteMultiVariableContext(com.sri.ai.grinder.sgdpllt.core.constraint.CompleteMultiVariableContext) And(com.sri.ai.grinder.sgdpllt.library.boole.And) DefaultMultiVariableConstraint(com.sri.ai.grinder.sgdpllt.core.constraint.DefaultMultiVariableConstraint) ZERO(com.sri.ai.expresso.helper.Expressions.ZERO) LinkedHashSet(java.util.LinkedHashSet) Sets(com.sri.ai.grinder.sgdpllt.library.set.Sets) Type(com.sri.ai.expresso.api.Type) NullaryFunction(com.sri.ai.util.base.NullaryFunction) Util.join(com.sri.ai.util.Util.join) SingleVariableConstraint(com.sri.ai.grinder.sgdpllt.api.SingleVariableConstraint) Simplifier(com.sri.ai.grinder.sgdpllt.rewriter.api.Simplifier) Collection(java.util.Collection) Util.list(com.sri.ai.util.Util.list) Set(java.util.Set) Expressions.getVariableReferences(com.sri.ai.expresso.helper.Expressions.getVariableReferences) Context(com.sri.ai.grinder.sgdpllt.api.Context) QuantifiedExpression(com.sri.ai.expresso.api.QuantifiedExpression) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) Beta(com.google.common.annotations.Beta) IndexExpressions(com.sri.ai.grinder.sgdpllt.library.indexexpression.IndexExpressions) Expressions.makeSymbol(com.sri.ai.expresso.helper.Expressions.makeSymbol) Util(com.sri.ai.util.Util) AssociativeCommutativeGroup(com.sri.ai.grinder.sgdpllt.group.AssociativeCommutativeGroup) Util.pickKElementsWithoutReplacement(com.sri.ai.util.Util.pickKElementsWithoutReplacement) TRUE(com.sri.ai.expresso.helper.Expressions.TRUE) BruteForceCommonInterpreter(com.sri.ai.grinder.sgdpllt.interpreter.BruteForceCommonInterpreter) AssignmentsIterator(com.sri.ai.grinder.helper.AssignmentsIterator) CompleteMultiVariableContext(com.sri.ai.grinder.sgdpllt.core.constraint.CompleteMultiVariableContext) Context(com.sri.ai.grinder.sgdpllt.api.Context) BruteForceCommonInterpreter(com.sri.ai.grinder.sgdpllt.interpreter.BruteForceCommonInterpreter) QuantifiedExpression(com.sri.ai.expresso.api.QuantifiedExpression) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) Expression(com.sri.ai.expresso.api.Expression) QuantifiedExpression(com.sri.ai.expresso.api.QuantifiedExpression) Simplifier(com.sri.ai.grinder.sgdpllt.rewriter.api.Simplifier) SubExpressionsDepthFirstIterator(com.sri.ai.expresso.helper.SubExpressionsDepthFirstIterator)

Example 9 with Theory

use of com.sri.ai.grinder.sgdpllt.api.Theory in project aic-praise by aic-sri-international.

the class UAIMARSolver method main.

public static void main(String[] args) throws IOException {
    if (args.length != 4) {
        throw new IllegalArgumentException("Usage: UAIMARSolver <file or directory with UAI-format files> <solution directory> <timeout in ms> equalities|difference_arithmetic");
    }
    File uaiInput = new File(args[0]);
    if (!uaiInput.exists()) {
        throw new IllegalArgumentException("File or directory specified does not exist: " + uaiInput.getAbsolutePath());
    }
    File solutionDir = new File(args[1]);
    if (!solutionDir.exists() || !solutionDir.isDirectory()) {
        throw new IllegalArgumentException("Solution directory is invalid: " + solutionDir.getAbsolutePath());
    }
    int maxSolverTimeInSeconds = Integer.parseInt(args[2]);
    Theory theory;
    if (args[3].equals("equalities")) {
        theory = new CompoundTheory(new PropositionalTheory(), new EqualityTheory(true, true));
    } else if (args[3].equals("difference_arithmetic")) {
        theory = new CompoundTheory(new PropositionalTheory(), new DifferenceArithmeticTheory(true, true));
    } else {
        throw new IllegalArgumentException("4-th argument must be either 'equalities' or 'difference_arithmetic'");
    }
    List<UAIModel> models = new ArrayList<>();
    Map<UAIModel, File> modelToFile = new HashMap<>();
    if (uaiInput.isDirectory()) {
        for (File uaiFile : uaiInput.listFiles((dir, name) -> name.endsWith(".uai"))) {
            UAIModel model = read(uaiFile, solutionDir);
            models.add(model);
            modelToFile.put(model, uaiFile);
        }
    } else {
        UAIModel model = read(uaiInput, solutionDir);
        models.add(model);
        modelToFile.put(model, uaiInput);
    }
    // Sort based on what we consider to be the simplest to hardest
    //Collections.sort(models, (model1, model2) -> Double.compare(model1.ratioUniqueTablesToTables(), model2.ratioUniqueTablesToTables()));
    //Collections.sort(models, (model1, model2) -> Integer.compare(model1.largestNumberOfFunctionTableEntries(), model2.largestNumberOfFunctionTableEntries()));
    Collections.sort(models, (model1, model2) -> Integer.compare(model1.totalNumberEntriesForAllFunctionTables(), model2.totalNumberEntriesForAllFunctionTables()));
    //Collections.sort(models, (model1, model2) -> Integer.compare(model1.numberTables(), model2.numberTables()));
    Map<String, Boolean> modelSolvedStatus = new LinkedHashMap<>();
    Map<String, Long> modelSolvedTime = new LinkedHashMap<>();
    System.out.println("#models read=" + models.size());
    final AtomicInteger cnt = new AtomicInteger(1);
    models.stream().forEach(model -> {
        System.out.println("Starting to Solve: " + modelToFile.get(model).getName() + " (" + cnt.getAndAdd(1) + " of " + models.size() + ")");
        long start = System.currentTimeMillis();
        boolean solved = solve(model, model.getEvidence(), model.getMARSolution(), maxSolverTimeInSeconds, theory);
        long took = (System.currentTimeMillis() - start);
        System.out.println("---- Took " + took + "ms. solved=" + solved);
        modelSolvedStatus.put(modelToFile.get(model).getName(), solved);
        modelSolvedTime.put(modelToFile.get(model).getName(), took);
    });
    System.out.println("MODELS SOLVE STATUS");
    modelSolvedStatus.entrySet().stream().forEach(e -> System.out.printf("%-25s %-5b %12sms.\n", e.getKey(), e.getValue(), modelSolvedTime.get(e.getKey())));
    System.out.println("SUMMARY");
    System.out.println("#models   solved=" + modelSolvedStatus.values().stream().filter(status -> status == true).count());
    System.out.println("#models unsolved=" + modelSolvedStatus.values().stream().filter(status -> status == false).count());
}
Also used : IntStream(java.util.stream.IntStream) Arrays(java.util.Arrays) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) MultiIndexQuantifierEliminator(com.sri.ai.grinder.sgdpllt.api.MultiIndexQuantifierEliminator) AtomicDouble(com.google.common.util.concurrent.AtomicDouble) Expressions(com.sri.ai.expresso.helper.Expressions) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) TimeoutException(java.util.concurrent.TimeoutException) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) Expression(com.sri.ai.expresso.api.Expression) FactorsAndTypes(com.sri.ai.praise.sgsolver.solver.FactorsAndTypes) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Future(java.util.concurrent.Future) Not(com.sri.ai.grinder.sgdpllt.library.boole.Not) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InferenceForFactorGraphAndEvidence(com.sri.ai.praise.sgsolver.solver.InferenceForFactorGraphAndEvidence) UAIUtil.convertGenericTableToInstance(com.sri.ai.praise.model.v1.imports.uai.UAIUtil.convertGenericTableToInstance) Map(java.util.Map) And(com.sri.ai.grinder.sgdpllt.library.boole.And) Division(com.sri.ai.grinder.sgdpllt.library.number.Division) ExecutorService(java.util.concurrent.ExecutorService) Equality(com.sri.ai.grinder.sgdpllt.library.Equality) IOException(java.io.IOException) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) Collectors(java.util.stream.Collectors) IfThenElse(com.sri.ai.grinder.sgdpllt.library.controlflow.IfThenElse) File(java.io.File) Executors(java.util.concurrent.Executors) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) Beta(com.google.common.annotations.Beta) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) GraphicalNetwork(com.sri.ai.praise.lang.grounded.common.GraphicalNetwork) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) UAIUtil.constructGenericTableExpressionUsingEqualities(com.sri.ai.praise.model.v1.imports.uai.UAIUtil.constructGenericTableExpressionUsingEqualities) FunctionTable(com.sri.ai.praise.lang.grounded.common.FunctionTable) Collections(java.util.Collections) FunctorConstants(com.sri.ai.grinder.sgdpllt.library.FunctorConstants) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) EqualityTheory(com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) DifferenceArithmeticTheory(com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory) ArrayList(java.util.ArrayList) PropositionalTheory(com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory) CompoundTheory(com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory) LinkedHashMap(java.util.LinkedHashMap) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) File(java.io.File)

Example 10 with Theory

use of com.sri.ai.grinder.sgdpllt.api.Theory in project aic-expresso by aic-sri-international.

the class SGDPLLT method solve.

/**
	 * @param group
	 * @param indices
	 * @param indicesCondition
	 * @param body
	 * @param context
	 * @return
	 */
@Override
public Expression solve(AssociativeCommutativeGroup group, List<Expression> indices, Expression indicesCondition, Expression body, Context context) {
    Theory theory = context.getTheory();
    Expression currentBody = body;
    int numberOfIndices = indices.size();
    if (numberOfIndices != 0) {
        // Re-use {@link SingleVariableConstraint} if condition is one.
        // TODO: eventually we want the algorithm to work so that it splitters may be entire constraints,
        // if they are found. Then this encoding would become superfluous,
        // and the condition could always be safely encoded in the body, since it would then be picked and re-used.
        // This would also re-use body if it happens to be a constraint.
        Pair<Expression, SingleVariableConstraint> bodyAndLastIndexConstraint = SGDPLLT.encodeConditionAsLastIndexConstraintIfPossibleOrInBodyOtherwise(group, indices, indicesCondition, body, theory, context);
        currentBody = bodyAndLastIndexConstraint.first;
        SingleVariableConstraint lastIndexConstraint = bodyAndLastIndexConstraint.second;
        if (lastIndexConstraint.isContradiction()) {
            return group.additiveIdentityElement();
        }
        for (int i = numberOfIndices - 1; i >= 0; i--) {
            // evaluate from inside out; this may change in the future
            Expression index = indices.get(i);
            SingleVariableConstraint constraintForThisIndex = i == numberOfIndices - 1 ? lastIndexConstraint : theory.makeSingleVariableConstraint(index, theory, context);
            ExpressionLiteralSplitterStepSolver quantifierEliminatorStepSolver = theory.getSingleVariableConstraintQuantifierEliminatorStepSolver(group, constraintForThisIndex, currentBody, context);
            if (quantifierEliminatorStepSolver != null) {
                currentBody = quantifierEliminatorStepSolver.solve(context);
            } else {
                // cannot eliminate this level, so reconstruct original expression up to this index
                throw new Error("Reconstruction of quantifier not yet eliminable not yet implemented.");
            // once implemented, must return  
            }
        }
    } else {
        currentBody = IfThenElse.make(indicesCondition, currentBody, group.additiveIdentityElement());
    }
    // Normalize final result.
    ExpressionLiteralSplitterStepSolver evaluator = theory.makeEvaluatorStepSolver(currentBody);
    currentBody = evaluator.solve(context);
    return currentBody;
}
Also used : SingleVariableConstraint(com.sri.ai.grinder.sgdpllt.api.SingleVariableConstraint) Theory(com.sri.ai.grinder.sgdpllt.api.Theory) Expression(com.sri.ai.expresso.api.Expression) ExpressionLiteralSplitterStepSolver(com.sri.ai.grinder.sgdpllt.api.ExpressionLiteralSplitterStepSolver) SingleVariableConstraint(com.sri.ai.grinder.sgdpllt.api.SingleVariableConstraint)

Aggregations

Theory (com.sri.ai.grinder.sgdpllt.api.Theory)29 Expression (com.sri.ai.expresso.api.Expression)21 Context (com.sri.ai.grinder.sgdpllt.api.Context)13 Type (com.sri.ai.expresso.api.Type)10 Map (java.util.Map)9 Beta (com.google.common.annotations.Beta)8 SingleVariableConstraint (com.sri.ai.grinder.sgdpllt.api.SingleVariableConstraint)8 CompoundTheory (com.sri.ai.grinder.sgdpllt.theory.compound.CompoundTheory)8 DifferenceArithmeticTheory (com.sri.ai.grinder.sgdpllt.theory.differencearithmetic.DifferenceArithmeticTheory)8 EqualityTheory (com.sri.ai.grinder.sgdpllt.theory.equality.EqualityTheory)8 PropositionalTheory (com.sri.ai.grinder.sgdpllt.theory.propositional.PropositionalTheory)8 Collection (java.util.Collection)8 Expressions.makeSymbol (com.sri.ai.expresso.helper.Expressions.makeSymbol)7 Expressions.parse (com.sri.ai.expresso.helper.Expressions.parse)7 AssociativeCommutativeGroup (com.sri.ai.grinder.sgdpllt.group.AssociativeCommutativeGroup)7 And (com.sri.ai.grinder.sgdpllt.library.boole.And)7 Util (com.sri.ai.util.Util)7 Util.join (com.sri.ai.util.Util.join)7 Util.list (com.sri.ai.util.Util.list)7 QuantifiedExpression (com.sri.ai.expresso.api.QuantifiedExpression)6