1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package zeus.concepts.fn;
26
27 import java.util.*;
28 import zeus.util.*;
29 import zeus.concepts.*;
30
31 /***
32 ArithmeticFn is used to store arthimetic over some condition
33 - made some alterations for 1.2.1 so that the precondition unification
34 bugs could be properly sorted (well, for the time being at least!)
35 Si.
36 */
37 public class ArithmeticFn extends ValueFunction implements NumericFn {
38 public static final int PLUS = 0;
39 public static final int MINUS = 1;
40 public static final int TIMES = 2;
41 public static final int DIVIDE = 3;
42 public static final int REM = 4;
43 public static final String[] operators = {
44 "+", "-", "*", "/", "%" };
45
46 public final static String[] legal_operands = {
47 "zeus.concepts.fn.MethodCallFn",
48 "zeus.concepts.fn.DefinedFn",
49 "zeus.concepts.fn.ArithmeticFn",
50 "zeus.concepts.fn.IntFn",
51 "zeus.concepts.fn.RealFn",
52 "zeus.concepts.fn.VarFn",
53 "zeus.concepts.fn.FieldFn",
54 "zeus.concepts.fn.ElseFn"
55 };
56 public final static String[] legal_unifiers = {
57 "zeus.concepts.fn.MethodCallFn",
58 "zeus.concepts.fn.DefinedFn",
59 "zeus.concepts.fn.ArithmeticFn",
60 "zeus.concepts.fn.IntFn",
61 "zeus.concepts.fn.RealFn",
62 "zeus.concepts.fn.VarFn",
63 "zeus.concepts.fn.FieldFn",
64
65 "zeus.concepts.fn.AndFn",
66 "zeus.concepts.fn.OrFn",
67 "zeus.concepts.fn.NotFn",
68 "zeus.concepts.fn.ImplyFn",
69 "zeus.concepts.fn.ElseFn"
70 };
71
72
73 protected ValueFunction[] args = new ValueFunction[2];
74 protected int op = -1;
75
76
77 /***
78 *resolve is here to handle unification for the postcondition to precondition maps -
79 *this will allow proper use of expressions when defining tasks.
80 *@since 1.2.1
81 *@author Simon Thompson
82 */
83 public void resolve (String attrName, ValueFunction val) {
84 ValueFunction lhs = args[0];
85 ValueFunction rhs = args[1];
86 debug ("in resolve");
87
88 if (lhs instanceof ArithmeticFn) {
89 debug ("recursing lhs");
90 ArithmeticFn lhsFn = (ArithmeticFn) lhs;
91 lhsFn.resolve (attrName,val);
92 }
93
94 else if (lhs instanceof VarFn) {
95 debug ("resolving lhs");
96 debug (" lhs = " + lhs.toString() + " val = " +val.toString() +" attrName = " + attrName);
97 if (lhs.toString().equals("?"+attrName)) {
98 lhs = val;
99 args[0] = lhs; }
100 debug (" lhs = " + lhs.toString() + " val = " +val.toString() +" attrName = " + attrName);
101 }
102
103 if (rhs instanceof ArithmeticFn) {
104 debug ("recursing rhs");
105 ArithmeticFn rhsFn = (ArithmeticFn) rhs;
106 rhsFn.resolve (attrName,val);
107 }
108
109 else if (rhs instanceof VarFn) {
110 debug ("resolving rhs");
111 if (rhs.toString().equals("?"+attrName)){
112 rhs = val;
113 args[1] = rhs;
114 }
115 }
116 }
117
118
119 public ArithmeticFn(ValueFunction lhs, ValueFunction rhs, String op) {
120 super(ARITH,3);
121 args[0] = lhs;
122 args[1] = rhs;
123
124 if ( (this.op = Misc.whichPosition(op,operators)) == -1 )
125 throw new IllegalArgumentException("Illegal operator " +
126 " in arithmetic function \'" + lhs + op + rhs + "\'");
127
128 String lname = lhs.getClass().getName();
129 String rname = rhs.getClass().getName();
130 if ( !Misc.member(lname,legal_operands) ||
131 !Misc.member(rname,legal_operands) )
132 throw new IllegalArgumentException("Illegal operands " +
133 " in arithmetic function \'" + lhs + op + rhs + "\'");
134 }
135
136
137 public ValueFunction getLHS () {
138 return args[0];
139 }
140
141 public ValueFunction getRHS () {
142 return args[1];
143 }
144
145
146
147
148 public ValueFunction mirror() {
149 return new ArithmeticFn(args[0].mirror(),args[1].mirror(),operators[op]);
150 }
151
152 public String toString() {
153 return "(" + args[0] + " " + operators[op] + " " + args[1] + ")";
154 }
155
156 public int getOperator() {
157 return op;
158 }
159
160
161 ValueFunction simplify() {
162 ValueFunction a, b;
163 a = args[0].simplify();
164 b = args[1].simplify();
165 return (a != args[0] || b != args[1])
166 ? new ArithmeticFn(a,b,operators[op]) : this;
167 }
168
169 Object getArg(int position) {
170 return args[position];
171 }
172
173
174
175
176 public boolean references(ValueFunction var) {
177 return args[0].references(var) || args[1].references(var);
178 }
179
180
181 public Vector variables() {
182 return Misc.union(args[0].variables(),args[1].variables());
183 }
184
185 public boolean isDeterminate() {
186 return args[0].isDeterminate() && args[1].isDeterminate();
187 }
188
189
190 ValueFunction normalize() {
191 ValueFunction a, b;
192 a = args[0].normalize();
193 b = args[1].normalize();
194 return (a != args[0] || b != args[1] )
195 ? new ArithmeticFn(a,b,operators[op]) : this;
196 }
197
198
199 public ValueFunction resolve(ResolutionContext c, Bindings b) {
200 ValueFunction x = args[0].resolve(c,b);
201 ValueFunction y = args[1].resolve(c,b);
202 return (new ArithmeticFn(x,y,operators[op])).evaluationFn();
203 }
204
205
206 public ValueFunction evaluationFn() {
207 if ( !isDeterminate() ) return this;
208 ValueFunction a, b;
209 double x = 0, y = 0, z = 0;
210 int left_type = REAL;
211 int right_type = REAL;
212 int return_type = REAL;
213 try {
214 a = args[0].evaluationFn();
215 b = args[1].evaluationFn();
216
217 if ( a instanceof IntFn ) {
218 x = (double) ((IntFn)a).getValue();
219 left_type = INT;
220 }
221 else
222 x = ((RealFn)a).getValue();
223
224 if ( b instanceof IntFn ) {
225 y = (double) ((IntFn)b).getValue();
226 right_type = INT;
227 }
228 else
229 y = ((RealFn)b).getValue();
230
231 if ( left_type == REAL || right_type == REAL )
232 return_type = REAL;
233 else
234 return_type = INT;
235 }
236 catch(Exception e) {
237 throw new IllegalArgumentException("Unknown operand type in " +
238 " arithmetic function \'" + this + "\'");
239 }
240
241 switch( op ) {
242 case PLUS:
243 z = x+y;
244 break;
245 case MINUS:
246 z = x-y;
247 break;
248 case TIMES:
249 z = x*y;
250 break;
251 case DIVIDE:
252 z = x/y;
253 break;
254 case REM:
255 z = (double) (((int)x) % ((int)y));
256 break;
257 default:
258 throw new IllegalArgumentException("Unknown operator in " +
259 " arithmetic function \'" + this + "\'");
260 }
261 if (op == REM || return_type == INT )
262 return new IntFn((int)z);
263 else
264 return new RealFn(z);
265 }
266
267
268 public ValueFunction duplicate(DuplicationTable table) {
269 return new ArithmeticFn(args[0].duplicate(table),args[1].duplicate(table),
270 operators[op]);
271 }
272
273
274 public boolean equals(Object any) {
275 if ( !(any instanceof ArithmeticFn) ) return false;
276 ArithmeticFn fn = (ArithmeticFn)any;
277
278 if ( op != ((ArithmeticFn)fn).getOperator() ) return false;
279
280 ValueFunction a = this.simplify();
281 ValueFunction b = fn.simplify();
282 return ((ValueFunction)a.getArg(0)).equals((ValueFunction)b.getArg(0)) &&
283 ((ValueFunction)a.getArg(1)).equals((ValueFunction)b.getArg(1));
284 }
285
286
287 ValueFunction unify(ValueFunction fn, Bindings b) {
288 String name = fn.getClass().getName();
289 if ( !Misc.member(name,legal_unifiers) ) {
290 throw new IllegalArgumentException("Illegal unification attempted: " +
291 this + " and " + fn );
292 }
293
294 ValueFunction x = null;
295
296 if ( (x = evaluationFn()) == this )
297 return new AndFn(this,fn);
298 else
299 return x.unifiesWith(fn,b);
300 }
301
302
303 public void debug (String str) {
304
305 }
306
307
308 }