1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10
11
12 /***
13 MODULE:
14 Compute
15 SHORTDESCRIPTION:
16 computes a pointwise expression over a field
17 CATEGORY:
18 Transformation
19 INPUTS:
20 expression; string; NULL; expression to evaluate
21 input0; value or field; NULL; input value
22 input1; value or field; NULL; input value
23 input2; value or field; NULL; input value
24 input3; value or field; NULL; input value
25 input4; value or field; NULL; input value
26 input5; value or field; NULL; input value
27 input6; value or field; NULL; input value
28 input7; value or field; NULL; input value
29 input8; value or field; NULL; input value
30 input9; value or field; NULL; input value
31 input10; value or field; NULL; input value
32 input11; value or field; NULL; input value
33 input12; value or field; NULL; input value
34 input13; value or field; NULL; input value
35 input14; value or field; NULL; input value
36 input15; value or field; NULL; input value
37 OUTPUTS:
38 output; value or field; NULL; output values
39 FLAGS:
40 BUGS:
41 Always expands constants into arrays
42 AUTHOR:
43 Channing Verbeck
44 END:
45 ***/
46
47 #include <string.h>
48 #include <dx/dx.h>
49 #include "_compute.h"
50 #include "_compputils.h"
51 #include "_compoper.h"
52
53
54 /* These are global variables to allow communication with the parser */
55 PTreeNode *_dxdcomputeTree = NULL;
56 CompInput _dxdcomputeInput[MAX_INPUTS] = {{0, (Class)NULL, NULL}};
57
58
59 /*
60 * A brief description of Compute:
61 *
62 * Compute is a general expression evaluator. It parses an input expression
63 * string and and performs that expression on its given inputs pointwise.
64 *
65 * Inputs are (as expressed in the MODULE section of this file) are the
66 * expression and input objects. The expression is in pseudo-C format and
67 * refers to input objects as $0, $1, etc. An example of the use of Compute
68 * follows:
69 * res = Compute ("mag ($0) * ($1 dot [1.,2,3])", vect1, vect2);
70 * This takes the magnitude of each element of `vect1', which is a set of
71 * n-vectors (where n is arbitrary), and multiplies that with the dot product
72 * of each point in `vect2' with [1.,2.,3.]. `Vect2' must be a set of
73 * 3-vectors. `Vect1' and `vect2' must have the same structure (i.e. they
74 * must both be the same Class objects, and the parts of the objects (if they
75 * are groups) must have the same number of elements.
76 *
77 * A `master' input is determined. It is the first input that is not a one
78 * element array. All inputs must match this input.
79 * If the parts of any input groups are fields,
80 * they are checked to see if the `positions' components are the same, and the
81 * user is warned if they are not; Compute doesn't map data onto the same
82 * positions. Trivial arrays (only one element) match with anything, and
83 * is applied to all positions.
84 *
85 * Types are strictly checked, with ints automatically promoted to floats
86 * if the expression fails type checking as is. Data elements are also
87 * checked to ensure they are of proper shape. Most binary operators work
88 * on non- * scalars on an element-by-element basis. Some operators enforce
89 * that objects be of the correct rank, and have the same shape (e.g. dot).
90 *
91 * Operators allowed are (where {} denotes optional, and ... denotes more
92 * allowed):
93 * int or float constants -- 0x123abc is hex, 012 is octal (018 == 16,
94 * and the user is warned), and 01.0 and 1.3e-1 are floats.
95 * $int -- (e.g. $3) referes to an input.
96 * [ expression {,expression...}] -- vector constructor, can construct
97 * vectors of vectors of ....
98 * $int0.int1 -- (e.g. $3.2) selects the int1 vector from input int0.
99 * int1 may be `x', `y', or `z', which represent 0, 1, and 2.
100 * binary expressions +, -, *, /, %, ^, dot, cross -- dot and cross
101 * only work on vectors of the same length.
102 * unary expressions - and +.
103 * logical binarys <, <=, >, >=, ==, !=, ||, && -- || and && only
104 * work on ints, the others return ints. 0 is FALSE, !0 is TRUE.
105 * logical unary ! -- not.
106 * int Cexpr? Texpr: Eexpr -- Conditional expression. Both Texpr and
107 * Eexpr are evaluated. Cexpr must be of type int.
108 * funcname({args {,args...}}) -- built in function. The following
109 * functions are supported:
110 * likevectorwithrank-1 select(vector, int)
111 * float sqrt(float)
112 * float pow(float,float)
113 * int pow(int,int)
114 * float sin(float)
115 * float cos(float)
116 * float tan(float)
117 * float ln(float)
118 * float log(float)
119 * int min(int{,int...})
120 * float min(float{,float...})
121 * int max(int{,int...})
122 * float max(float{,float...})
123 * float floor(float)
124 * float ceil(float)
125 * float trunc(float)
126 * float rint(float)
127 * float exp(float)
128 * float tanh(float)
129 * float sinh(float)
130 * float cosh(float)
131 * float acos(float)
132 * float asin(float)
133 * float atan(float)
134 * float atan2(float, float)
135 * float mag(float vector)
136 * int mag(int vector)
137 * float vector norm(float vector)
138 * int vector norm(int vector)
139 * float abs(float)
140 * int abs(int)
141 * int int(float)
142 * float float(int)
143 * float or int real(complex)
144 * float or int real(quaternion)
145 * float or int imag(complex)
146 * complex complex(float)
147 * complex complex(int)
148 * complex complex(float, float)
149 * complex complex(int, int)
150 * float or int imagi(quaternion)
151 * float or int imagj(quaternion)
152 * float or int imagk(quaternion)
153 * quaternion quaternion(float)
154 * quaternion quaternion(int)
155 * quaternion quaternion(float, float, float, float)
156 * quaternion quaternion(int, int, int, int)
157 * int sign(float)
158 *
159 * Compute Internals:
160 * The expression is parsed using a YACC built parser and a home-grown
161 * lexor into _parseTree. The inputs is then verified to be of the same
162 * structure, and a copy of this structure is created into inputStruct.
163 * This structure contains a node for each object in the group hierarchy,
164 * and an output object (a copy of the master input) is created. Each
165 * object in the heirarchy which is not a Generic Group and not a member
166 * of a Homogeneous Group has a copy of the parse tree. The objects with parse
167 * trees are typechecked and executed. For more details on that process,
168 * see _compoper.c. The results are inserted into inputStruct.output, which
169 * is the result of Compute.
170 */
171
172 int _dxfccparse();
173
174 int
m_Compute(Object * in,Object * out)175 m_Compute(Object *in, Object *out)
176 {
177 char *expression;
178 ObjStruct *inputStruct;
179
180 _dxfComputeInitInputs(_dxdcomputeInput);
181
182 out[0] = NULL;
183
184 if (in[0] == NULL) {
185 DXSetError (ERROR_BAD_PARAMETER, "#10200", "expression");
186 return ERROR;
187 }
188
189 if (!DXExtractString (in[0], &expression)) {
190 DXSetError (ERROR_BAD_TYPE, "#10200", "expression");
191 return ERROR;
192 }
193
194 if (strlen(expression) == 0) {
195 DXSetError (ERROR_BAD_PARAMETER, "#10210", expression, "expression");
196 return ERROR;
197 }
198
199 /* Build parse tree into _dxdcomputeTree */
200 _dxfccinput (expression);
201 if (_dxfccparse () == 1 || _dxdcomputeTree == NULL) {
202 return (ERROR);
203 }
204
205 #if COMP_DEBUG
206 _dxfComputeDumpParseTree (_dxdcomputeTree, 0);
207 #endif
208
209 /* Get the inputs used in the expression */
210 if ((inputStruct = _dxfComputeGetInputs (in + 1, _dxdcomputeInput)) == NULL) {
211 _dxfComputeFreeTree(_dxdcomputeTree);
212 return (ERROR);
213 }
214
215 #if COMP_DEBUG
216 _dxfComputeDumpInputs (_dxdcomputeInput, inputStruct);
217 #endif
218
219 /* Type check the expression with the inputs, returning an output
220 * description in the top tree element, and execute the tree with
221 * respect to that parse tree.
222 */
223 if (_dxfComputeExecute (_dxdcomputeTree, inputStruct) == ERROR) {
224 if (inputStruct->class != CLASS_ARRAY)
225 DXDelete(inputStruct->output);
226 _dxfComputeFreeTree (_dxdcomputeTree);
227 _dxfComputeFreeObjStruct (inputStruct);
228 return (ERROR);
229 }
230 out[0] = inputStruct->output;
231
232 _dxfComputeFreeTree (_dxdcomputeTree);
233 _dxfComputeFreeObjStruct (inputStruct);
234 return (OK);
235 }
236