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