View Javadoc

1   package cz.cuni.amis.pogamut.sposh.engine;
2   
3   import cz.cuni.amis.pogamut.sposh.elements.Arguments;
4   import cz.cuni.amis.pogamut.sposh.elements.LapPath;
5   import cz.cuni.amis.pogamut.sposh.elements.PrimitiveCall;
6   import cz.cuni.amis.pogamut.sposh.elements.Result;
7   import cz.cuni.amis.pogamut.sposh.elements.Sense;
8   import cz.cuni.amis.pogamut.sposh.elements.Sense.Predicate;
9   import cz.cuni.amis.pogamut.sposh.executor.IWorkExecutor;
10  
11  /**
12   * Class for storing result of one sense evaluation. This stores value returned 
13   * by a sense, not the result of sense comparison with a value.
14   * 
15   * E.g.: we have sense "health" and {@link PrimitiveCall} "(health < 25)"; the sense
16   * will be evaluated to 56, but the sensecall is false. The sense result is 
17   * therefore 56.
18   */
19  class SenseResult {
20  
21      /** Name of sense that was evaluated */
22      public final String name;
23      /** Was this sense successful? */
24      private final boolean success;
25  
26      /**
27       * Create new result of sense with some value
28       * @param name name of sense that was fired
29       * @param success was the sense successful?
30       */
31      SenseResult(String name, boolean success) {
32          this.name = name;
33          this.success = success;
34      }
35  
36      /**
37       * Check is this sense was successful. This is different from value of 
38       * sensecall.
39       * @return if this sense was evaluated to be true
40       */
41      public boolean wasSuccessful() {
42          return success;
43      }
44  }
45  
46  /**
47   * Evaluate the primitive (either sesnee or action).
48   * <p>
49   * Possible format of the primitive (in the plan):
50   * <ul>
51   *  <li>primitive</li>
52   *  <li>(primitive($variable,...))</li>
53   *  <li>(primitive($variable,...) value)</li>
54   *  <li>(primitive($variable,...) value predicate)</li>
55   *  <li>(primitive)</li>
56   *  <li>(primitive value)</li>
57   *  <li>(primitive value predicate)</li>
58   * </ul>
59   * @author Honza
60   */
61  final class SenseExecutor extends AbstractExecutor {
62  
63      private PrimitiveCall senseCall;
64      private Predicate predicate;
65      /**
66       * When evaluating the sense result, should I compare it with the operand?
67       * XXX: if operand is true and predicate ==, don't compare
68       */
69      private final boolean compare = true;
70      private Object operand;
71  
72      /**
73       * Create new sense executor.
74       * @param sense sense that is going to be executed
75       * @param ctx variable context for the sense
76       * @param log logger to record actions of this executor
77       */
78      SenseExecutor(Sense sense, LapPath sensePath, VariableContext ctx, EngineLog log) {
79          super(sensePath, ctx, log);
80  
81          assert sensePath.traversePath(sense.getRootNode()) == sense;
82          
83          senseCall = sense.getSenseCall();
84          predicate = sense.getPredicate();
85          operand = sense.getOperand();
86      }
87  
88      /**
89       * Evaluate the primitive
90       * @return Result object with information about sense evaluation
91       */
92      public SenseResult fire(IWorkExecutor workExecuter) {
93          engineLog.fine("Fire: " + toString());
94          engineLog.pathReached(path);
95          
96          String senseName = senseCall.getName();
97  
98          Object primitiveResult = workExecuter.executeSense(senseName, new VariableContext(ctx, senseCall.getParameters()));
99  
100         boolean res;
101         // If there is nothing to compare with, use only result.
102         if (!compare) {
103             res = Result.isTrue(primitiveResult);
104         } else {
105             res = evaluateComparison(primitiveResult, predicate, operand);
106         }
107         return new SenseResult(senseName, res);
108     }
109 
110     /**
111      * Compare two values.
112      * <p>
113      * This thing deserves a lot of TLC. I try to abide to python convention:
114      *
115      * http://docs.python.org/reference/expressions.html#notin
116      * http://docs.python.org/library/stdtypes.html
117      *
118      * <p>
119      * numbers: numint, numfloat
120      *
121      * @param value1 nonempty value
122      * @param predicate predicate that will be used for comparison
123      * @param value2 nonempty value
124      * @return
125      */
126     static boolean evaluateComparison(Object operand1, Predicate predicate, Object operand2) {
127         String comparison = operand1 + " " + predicate + " " + operand2;
128         switch (predicate) {
129             case DEFAULT:  // default predicate is equal
130             case EQUAL:
131                 return Result.equal(operand1, operand2);
132             case NOT_EQUAL:
133                 return !Result.equal(operand1, operand2);
134             case LOWER:
135                 return Result.compare(operand1, operand2) < 0;
136             case GREATER:
137                 return Result.compare(operand1, operand2) > 0;
138             case LOWER_OR_EQUAL:
139                 return Result.equal(operand1, operand2) || Result.compare(operand1, operand2) < 0;
140             case GREATER_OR_EQUAL:
141                 return Result.equal(operand1, operand2) || Result.compare(operand1, operand2) > 0;
142             default:
143                 throw new IllegalArgumentException("Predicate operation \"" + predicate + "\" is implemented.");
144         }
145     }
146 
147     @Override
148     public String toString() {
149         StringBuilder sb = new StringBuilder("SenseExecutor[(");
150 
151         sb.append(senseCall.getName());
152         sb.append('(');
153         boolean first = true;
154         for (Arguments.Argument parameter : senseCall.getParameters()) {
155             if (!first) {
156                 sb.append(", ");
157             }
158             sb.append(parameter.getParameterName());
159             first = false;
160         }
161         sb.append(')');
162 
163         if (compare) {
164             sb.append(' ');
165             sb.append(predicate);
166 
167             sb.append(' ');
168             sb.append(operand);
169         }
170 
171         sb.append(')');
172         sb.append(']');
173         return sb.toString();
174     }
175 }