epanet-plus 0.0.1__cp39-cp39-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of epanet-plus might be problematic. Click here for more details.
- docs/conf.py +67 -0
- epanet-msx-src/dispersion.h +27 -0
- epanet-msx-src/hash.c +107 -0
- epanet-msx-src/hash.h +28 -0
- epanet-msx-src/include/epanetmsx.h +104 -0
- epanet-msx-src/include/epanetmsx_export.h +42 -0
- epanet-msx-src/mathexpr.c +937 -0
- epanet-msx-src/mathexpr.h +39 -0
- epanet-msx-src/mempool.c +204 -0
- epanet-msx-src/mempool.h +24 -0
- epanet-msx-src/msxchem.c +1285 -0
- epanet-msx-src/msxcompiler.c +368 -0
- epanet-msx-src/msxdict.h +42 -0
- epanet-msx-src/msxdispersion.c +586 -0
- epanet-msx-src/msxerr.c +116 -0
- epanet-msx-src/msxfile.c +260 -0
- epanet-msx-src/msxfuncs.c +175 -0
- epanet-msx-src/msxfuncs.h +35 -0
- epanet-msx-src/msxinp.c +1504 -0
- epanet-msx-src/msxout.c +398 -0
- epanet-msx-src/msxproj.c +791 -0
- epanet-msx-src/msxqual.c +2011 -0
- epanet-msx-src/msxrpt.c +400 -0
- epanet-msx-src/msxtank.c +422 -0
- epanet-msx-src/msxtoolkit.c +1164 -0
- epanet-msx-src/msxtypes.h +551 -0
- epanet-msx-src/msxutils.c +524 -0
- epanet-msx-src/msxutils.h +56 -0
- epanet-msx-src/newton.c +158 -0
- epanet-msx-src/newton.h +34 -0
- epanet-msx-src/rk5.c +287 -0
- epanet-msx-src/rk5.h +39 -0
- epanet-msx-src/ros2.c +293 -0
- epanet-msx-src/ros2.h +35 -0
- epanet-msx-src/smatrix.c +816 -0
- epanet-msx-src/smatrix.h +29 -0
- epanet-src/AUTHORS +60 -0
- epanet-src/LICENSE +21 -0
- epanet-src/enumstxt.h +151 -0
- epanet-src/epanet.c +5937 -0
- epanet-src/epanet2.c +961 -0
- epanet-src/epanet2.def +131 -0
- epanet-src/errors.dat +79 -0
- epanet-src/flowbalance.c +186 -0
- epanet-src/funcs.h +219 -0
- epanet-src/genmmd.c +1000 -0
- epanet-src/hash.c +177 -0
- epanet-src/hash.h +28 -0
- epanet-src/hydcoeffs.c +1303 -0
- epanet-src/hydraul.c +1164 -0
- epanet-src/hydsolver.c +781 -0
- epanet-src/hydstatus.c +442 -0
- epanet-src/include/epanet2.h +466 -0
- epanet-src/include/epanet2_2.h +1962 -0
- epanet-src/include/epanet2_enums.h +518 -0
- epanet-src/inpfile.c +884 -0
- epanet-src/input1.c +672 -0
- epanet-src/input2.c +970 -0
- epanet-src/input3.c +2265 -0
- epanet-src/leakage.c +527 -0
- epanet-src/mempool.c +146 -0
- epanet-src/mempool.h +24 -0
- epanet-src/output.c +853 -0
- epanet-src/project.c +1691 -0
- epanet-src/quality.c +695 -0
- epanet-src/qualreact.c +800 -0
- epanet-src/qualroute.c +696 -0
- epanet-src/report.c +1559 -0
- epanet-src/rules.c +1500 -0
- epanet-src/smatrix.c +871 -0
- epanet-src/text.h +508 -0
- epanet-src/types.h +928 -0
- epanet-src/util/cstr_helper.c +59 -0
- epanet-src/util/cstr_helper.h +38 -0
- epanet-src/util/errormanager.c +92 -0
- epanet-src/util/errormanager.h +39 -0
- epanet-src/util/filemanager.c +212 -0
- epanet-src/util/filemanager.h +81 -0
- epanet-src/validate.c +408 -0
- epanet.cp39-win32.pyd +0 -0
- epanet_plus/VERSION +1 -0
- epanet_plus/__init__.py +8 -0
- epanet_plus/epanet_plus.c +118 -0
- epanet_plus/epanet_toolkit.py +2730 -0
- epanet_plus/epanet_wrapper.py +2414 -0
- epanet_plus/include/epanet_plus.h +9 -0
- epanet_plus-0.0.1.dist-info/METADATA +152 -0
- epanet_plus-0.0.1.dist-info/RECORD +105 -0
- epanet_plus-0.0.1.dist-info/WHEEL +5 -0
- epanet_plus-0.0.1.dist-info/licenses/LICENSE +21 -0
- epanet_plus-0.0.1.dist-info/top_level.txt +10 -0
- examples/basic_usage.py +35 -0
- python-extension/ext.c +344 -0
- python-extension/pyepanet.c +2133 -0
- python-extension/pyepanet.h +143 -0
- python-extension/pyepanet2.c +1823 -0
- python-extension/pyepanet2.h +141 -0
- python-extension/pyepanet_plus.c +37 -0
- python-extension/pyepanet_plus.h +4 -0
- python-extension/pyepanetmsx.c +388 -0
- python-extension/pyepanetmsx.h +35 -0
- tests/test_epanet.py +16 -0
- tests/test_epanetmsx.py +36 -0
- tests/test_epyt.py +114 -0
- tests/test_load_inp_from_buffer.py +18 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
** MODULE: MATHEXPR.C
|
|
3
|
+
** PROJECT: EPANET-MSX
|
|
4
|
+
** DESCRIPTION: Evaluates symbolic mathematical expression consisting
|
|
5
|
+
** of numbers, variable names, math functions & arithmetic
|
|
6
|
+
** operators.
|
|
7
|
+
** AUTHORS: see AUTHORS
|
|
8
|
+
** Copyright: see AUTHORS
|
|
9
|
+
** License: see LICENSE
|
|
10
|
+
** VERSION: 2.0.00
|
|
11
|
+
** LAST UPDATE: 09/02/2022
|
|
12
|
+
******************************************************************************/
|
|
13
|
+
/*
|
|
14
|
+
** Operand codes:
|
|
15
|
+
** 1 = (
|
|
16
|
+
** 2 = )
|
|
17
|
+
** 3 = +
|
|
18
|
+
** 4 = - (subtraction)
|
|
19
|
+
** 5 = *
|
|
20
|
+
** 6 = /
|
|
21
|
+
** 7 = number
|
|
22
|
+
** 8 = user-defined variable
|
|
23
|
+
** 9 = - (negative)
|
|
24
|
+
** 10 = cos
|
|
25
|
+
** 11 = sin
|
|
26
|
+
** 12 = tan
|
|
27
|
+
** 13 = cot
|
|
28
|
+
** 14 = abs
|
|
29
|
+
** 15 = sgn
|
|
30
|
+
** 16 = sqrt
|
|
31
|
+
** 17 = log
|
|
32
|
+
** 18 = exp
|
|
33
|
+
** 19 = asin
|
|
34
|
+
** 20 = acos
|
|
35
|
+
** 21 = atan
|
|
36
|
+
** 22 = acot
|
|
37
|
+
** 23 = sinh
|
|
38
|
+
** 24 = cosh
|
|
39
|
+
** 25 = tanh
|
|
40
|
+
** 26 = coth
|
|
41
|
+
** 27 = log10
|
|
42
|
+
** 28 = step (x<=0 ? 0 : 1)
|
|
43
|
+
** 31 = ^
|
|
44
|
+
******************************************************************************/
|
|
45
|
+
#define _CRT_SECURE_NO_WARNINGS
|
|
46
|
+
|
|
47
|
+
#include <ctype.h>
|
|
48
|
+
#include <string.h>
|
|
49
|
+
#include <stdlib.h>
|
|
50
|
+
#include <stdio.h>
|
|
51
|
+
#include <math.h>
|
|
52
|
+
|
|
53
|
+
#include "mathexpr.h"
|
|
54
|
+
|
|
55
|
+
#define MAX_STACK_SIZE 1024
|
|
56
|
+
|
|
57
|
+
//***************************************************
|
|
58
|
+
#define MAX_TERM_SIZE 1024
|
|
59
|
+
struct MathTerm
|
|
60
|
+
{
|
|
61
|
+
char s[MAX_TERM_SIZE];
|
|
62
|
+
};
|
|
63
|
+
typedef struct MathTerm Term;
|
|
64
|
+
//***************************************************
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
// Local declarations
|
|
68
|
+
//--------------------
|
|
69
|
+
// Structure for binary tree representation of math expression
|
|
70
|
+
struct TreeNode
|
|
71
|
+
{
|
|
72
|
+
int opcode; // operator code
|
|
73
|
+
int ivar; // variable index
|
|
74
|
+
double fvalue; // numerical value
|
|
75
|
+
struct TreeNode* left; // left sub-tree of tokenized formula
|
|
76
|
+
struct TreeNode* right; // right sub-tree of tokenized formula
|
|
77
|
+
};
|
|
78
|
+
typedef struct TreeNode ExprTree;
|
|
79
|
+
|
|
80
|
+
// Local variables
|
|
81
|
+
//----------------
|
|
82
|
+
static int Err;
|
|
83
|
+
static int Bc;
|
|
84
|
+
static int PrevLex, CurLex;
|
|
85
|
+
static int Len, Pos;
|
|
86
|
+
static char* S;
|
|
87
|
+
static char Token[255];
|
|
88
|
+
static int Ivar;
|
|
89
|
+
static double Fvalue;
|
|
90
|
+
|
|
91
|
+
// math function names
|
|
92
|
+
char* MathFunc[] = { "COS", "SIN", "TAN", "COT", "ABS", "SGN",
|
|
93
|
+
"SQRT", "LOG", "EXP", "ASIN", "ACOS", "ATAN",
|
|
94
|
+
"ACOT", "SINH", "COSH", "TANH", "COTH", "LOG10",
|
|
95
|
+
"STEP", NULL };
|
|
96
|
+
|
|
97
|
+
// Local functions
|
|
98
|
+
//----------------
|
|
99
|
+
static int sametext(char*, char*);
|
|
100
|
+
static int isDigit(char);
|
|
101
|
+
static int isLetter(char);
|
|
102
|
+
static void getToken(void);
|
|
103
|
+
static int getMathFunc(void);
|
|
104
|
+
static int getVariable(void);
|
|
105
|
+
static int getOperand(void);
|
|
106
|
+
static int getLex(void);
|
|
107
|
+
static double getNumber(void);
|
|
108
|
+
static ExprTree* newNode(void);
|
|
109
|
+
static ExprTree* getSingleOp(int*);
|
|
110
|
+
static ExprTree* getOp(int*);
|
|
111
|
+
static ExprTree* getTree(void);
|
|
112
|
+
static void traverseTree(ExprTree*, MathExpr**);
|
|
113
|
+
static void deleteTree(ExprTree*);
|
|
114
|
+
|
|
115
|
+
// Callback functions
|
|
116
|
+
static int (*getVariableIndex) (char*); // return index of named variable
|
|
117
|
+
static double (*getVariableValue) (int); // return value of indexed variable
|
|
118
|
+
|
|
119
|
+
//=============================================================================
|
|
120
|
+
|
|
121
|
+
int sametext(char* s1, char* s2)
|
|
122
|
+
/*
|
|
123
|
+
** Purpose:
|
|
124
|
+
** performs case insensitive comparison of two strings.
|
|
125
|
+
**
|
|
126
|
+
** Input:
|
|
127
|
+
** s1 = character string
|
|
128
|
+
** s2 = character string.
|
|
129
|
+
**
|
|
130
|
+
** Returns:
|
|
131
|
+
** 1 if strings are the same, 0 otherwise.
|
|
132
|
+
*/
|
|
133
|
+
{
|
|
134
|
+
int i;
|
|
135
|
+
for (i = 0; toupper(s1[i]) == toupper(s2[i]); i++)
|
|
136
|
+
if (!s1[i + 1] && !s2[i + 1]) return(1);
|
|
137
|
+
return(0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//=============================================================================
|
|
141
|
+
|
|
142
|
+
int isDigit(char c)
|
|
143
|
+
{
|
|
144
|
+
if (c >= '1' && c <= '9') return 1;
|
|
145
|
+
if (c == '0') return 1;
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//=============================================================================
|
|
150
|
+
|
|
151
|
+
int isLetter(char c)
|
|
152
|
+
{
|
|
153
|
+
if (c >= 'a' && c <= 'z') return 1;
|
|
154
|
+
if (c >= 'A' && c <= 'Z') return 1;
|
|
155
|
+
if (c == '_') return 1;
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
//=============================================================================
|
|
160
|
+
|
|
161
|
+
void getToken()
|
|
162
|
+
{
|
|
163
|
+
char c[] = " ";
|
|
164
|
+
Token[0] = '\0';
|
|
165
|
+
while (Pos <= Len &&
|
|
166
|
+
(isLetter(S[Pos]) || isDigit(S[Pos])))
|
|
167
|
+
{
|
|
168
|
+
c[0] = S[Pos];
|
|
169
|
+
strcat(Token, c);
|
|
170
|
+
Pos++;
|
|
171
|
+
}
|
|
172
|
+
Pos--;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
//=============================================================================
|
|
176
|
+
|
|
177
|
+
int getMathFunc()
|
|
178
|
+
{
|
|
179
|
+
int i = 0;
|
|
180
|
+
while (MathFunc[i] != NULL)
|
|
181
|
+
{
|
|
182
|
+
if (sametext(MathFunc[i], Token)) return i + 10;
|
|
183
|
+
i++;
|
|
184
|
+
}
|
|
185
|
+
return(0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//=============================================================================
|
|
189
|
+
|
|
190
|
+
int getVariable()
|
|
191
|
+
{
|
|
192
|
+
if (!getVariableIndex) return 0;
|
|
193
|
+
Ivar = getVariableIndex(Token);
|
|
194
|
+
if (Ivar >= 0) return 8;
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//=============================================================================
|
|
199
|
+
|
|
200
|
+
double getNumber()
|
|
201
|
+
{
|
|
202
|
+
char c[] = " ";
|
|
203
|
+
char sNumber[255];
|
|
204
|
+
int errflag = 0;
|
|
205
|
+
int decimalCount = 0;
|
|
206
|
+
|
|
207
|
+
/* --- get whole number portion of number */
|
|
208
|
+
sNumber[0] = '\0';
|
|
209
|
+
while (Pos < Len && isDigit(S[Pos]))
|
|
210
|
+
{
|
|
211
|
+
c[0] = S[Pos];
|
|
212
|
+
strcat(sNumber, c);
|
|
213
|
+
Pos++;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* --- get fractional portion of number */
|
|
217
|
+
if (Pos < Len)
|
|
218
|
+
{
|
|
219
|
+
if (S[Pos] == '.')
|
|
220
|
+
{
|
|
221
|
+
decimalCount++;
|
|
222
|
+
if (decimalCount > 1) Err = 1;
|
|
223
|
+
strcat(sNumber, ".");
|
|
224
|
+
Pos++;
|
|
225
|
+
while (Pos < Len && isDigit(S[Pos]))
|
|
226
|
+
{
|
|
227
|
+
c[0] = S[Pos];
|
|
228
|
+
strcat(sNumber, c);
|
|
229
|
+
Pos++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* --- get exponent */
|
|
234
|
+
if (Pos < Len && (S[Pos] == 'e' || S[Pos] == 'E'))
|
|
235
|
+
{
|
|
236
|
+
strcat(sNumber, "E");
|
|
237
|
+
Pos++;
|
|
238
|
+
if (Pos >= Len) errflag = 1;
|
|
239
|
+
else
|
|
240
|
+
{
|
|
241
|
+
if (S[Pos] == '-' || S[Pos] == '+')
|
|
242
|
+
{
|
|
243
|
+
c[0] = S[Pos];
|
|
244
|
+
strcat(sNumber, c);
|
|
245
|
+
Pos++;
|
|
246
|
+
}
|
|
247
|
+
if (Pos >= Len || !isDigit(S[Pos])) errflag = 1;
|
|
248
|
+
else while (Pos < Len && isDigit(S[Pos]))
|
|
249
|
+
{
|
|
250
|
+
c[0] = S[Pos];
|
|
251
|
+
strcat(sNumber, c);
|
|
252
|
+
Pos++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
Pos--;
|
|
258
|
+
if (errflag) return 0;
|
|
259
|
+
else return atof(sNumber);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
//=============================================================================
|
|
263
|
+
|
|
264
|
+
int getOperand()
|
|
265
|
+
{
|
|
266
|
+
int code;
|
|
267
|
+
switch (S[Pos])
|
|
268
|
+
{
|
|
269
|
+
case '(': code = 1; break;
|
|
270
|
+
case ')': code = 2; break;
|
|
271
|
+
case '+': code = 3; break;
|
|
272
|
+
case '-': code = 4;
|
|
273
|
+
if (Pos < Len - 1 &&
|
|
274
|
+
isDigit(S[Pos + 1]) &&
|
|
275
|
+
(CurLex <= 6 || CurLex == 31))
|
|
276
|
+
{
|
|
277
|
+
Pos++;
|
|
278
|
+
Fvalue = -getNumber();
|
|
279
|
+
code = 7;
|
|
280
|
+
}
|
|
281
|
+
break;
|
|
282
|
+
case '*': code = 5; break;
|
|
283
|
+
case '/': code = 6; break;
|
|
284
|
+
case '^': code = 31; break;
|
|
285
|
+
default: code = 0;
|
|
286
|
+
}
|
|
287
|
+
return code;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//=============================================================================
|
|
291
|
+
|
|
292
|
+
int getLex()
|
|
293
|
+
{
|
|
294
|
+
int n;
|
|
295
|
+
|
|
296
|
+
/* --- skip spaces */
|
|
297
|
+
while (Pos < Len && S[Pos] == ' ') Pos++;
|
|
298
|
+
if (Pos >= Len) return 0;
|
|
299
|
+
|
|
300
|
+
/* --- check for operand */
|
|
301
|
+
n = getOperand();
|
|
302
|
+
|
|
303
|
+
/* --- check for function/variable/number */
|
|
304
|
+
if (n == 0)
|
|
305
|
+
{
|
|
306
|
+
if (isLetter(S[Pos]))
|
|
307
|
+
{
|
|
308
|
+
getToken();
|
|
309
|
+
n = getMathFunc();
|
|
310
|
+
if (n == 0) n = getVariable();
|
|
311
|
+
}
|
|
312
|
+
else if (S[Pos] == '.' || isDigit(S[Pos]))
|
|
313
|
+
{
|
|
314
|
+
n = 7;
|
|
315
|
+
Fvalue = getNumber();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
Pos++;
|
|
319
|
+
PrevLex = CurLex;
|
|
320
|
+
CurLex = n;
|
|
321
|
+
return n;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
//=============================================================================
|
|
325
|
+
|
|
326
|
+
ExprTree* newNode()
|
|
327
|
+
{
|
|
328
|
+
ExprTree* node;
|
|
329
|
+
node = (ExprTree*)malloc(sizeof(ExprTree));
|
|
330
|
+
if (!node) Err = 2;
|
|
331
|
+
else
|
|
332
|
+
{
|
|
333
|
+
node->opcode = 0;
|
|
334
|
+
node->ivar = -1;
|
|
335
|
+
node->fvalue = 0.;
|
|
336
|
+
node->left = NULL;
|
|
337
|
+
node->right = NULL;
|
|
338
|
+
}
|
|
339
|
+
return node;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
//=============================================================================
|
|
343
|
+
|
|
344
|
+
ExprTree* getSingleOp(int* lex)
|
|
345
|
+
{
|
|
346
|
+
int opcode;
|
|
347
|
+
ExprTree* left;
|
|
348
|
+
ExprTree* node;
|
|
349
|
+
|
|
350
|
+
/* --- open parenthesis, so continue to grow the tree */
|
|
351
|
+
if (*lex == 1)
|
|
352
|
+
{
|
|
353
|
+
Bc++;
|
|
354
|
+
left = getTree();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
else
|
|
358
|
+
{
|
|
359
|
+
/* --- Error if not a singleton operand */
|
|
360
|
+
if (*lex < 7 || *lex == 9 || *lex > 30)
|
|
361
|
+
{
|
|
362
|
+
Err = 1;
|
|
363
|
+
return NULL;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
opcode = *lex;
|
|
367
|
+
|
|
368
|
+
/* --- simple number or variable name */
|
|
369
|
+
if (*lex == 7 || *lex == 8)
|
|
370
|
+
{
|
|
371
|
+
left = newNode();
|
|
372
|
+
left->opcode = opcode;
|
|
373
|
+
if (*lex == 7) left->fvalue = Fvalue;
|
|
374
|
+
if (*lex == 8) left->ivar = Ivar;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* --- function which must have a '(' after it */
|
|
378
|
+
else
|
|
379
|
+
{
|
|
380
|
+
*lex = getLex();
|
|
381
|
+
if (*lex != 1)
|
|
382
|
+
{
|
|
383
|
+
Err = 1;
|
|
384
|
+
return NULL;
|
|
385
|
+
}
|
|
386
|
+
Bc++;
|
|
387
|
+
left = newNode();
|
|
388
|
+
left->left = getTree();
|
|
389
|
+
left->opcode = opcode;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
*lex = getLex();
|
|
393
|
+
|
|
394
|
+
/* --- exponentiation */
|
|
395
|
+
if (*lex == 31)
|
|
396
|
+
{
|
|
397
|
+
node = newNode();
|
|
398
|
+
node->left = left;
|
|
399
|
+
node->opcode = *lex;
|
|
400
|
+
*lex = getLex();
|
|
401
|
+
node->right = getSingleOp(lex);
|
|
402
|
+
left = node;
|
|
403
|
+
}
|
|
404
|
+
return left;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
//=============================================================================
|
|
408
|
+
|
|
409
|
+
ExprTree* getOp(int* lex)
|
|
410
|
+
{
|
|
411
|
+
int opcode;
|
|
412
|
+
ExprTree* left;
|
|
413
|
+
ExprTree* right;
|
|
414
|
+
ExprTree* node;
|
|
415
|
+
int neg = 0;
|
|
416
|
+
|
|
417
|
+
*lex = getLex();
|
|
418
|
+
if (PrevLex == 0 || PrevLex == 1)
|
|
419
|
+
{
|
|
420
|
+
if (*lex == 4)
|
|
421
|
+
{
|
|
422
|
+
neg = 1;
|
|
423
|
+
*lex = getLex();
|
|
424
|
+
}
|
|
425
|
+
else if (*lex == 3) *lex = getLex();
|
|
426
|
+
}
|
|
427
|
+
left = getSingleOp(lex);
|
|
428
|
+
while (*lex == 5 || *lex == 6)
|
|
429
|
+
{
|
|
430
|
+
opcode = *lex;
|
|
431
|
+
*lex = getLex();
|
|
432
|
+
right = getSingleOp(lex);
|
|
433
|
+
node = newNode();
|
|
434
|
+
if (Err) return NULL;
|
|
435
|
+
node->left = left;
|
|
436
|
+
node->right = right;
|
|
437
|
+
node->opcode = opcode;
|
|
438
|
+
left = node;
|
|
439
|
+
}
|
|
440
|
+
if (neg)
|
|
441
|
+
{
|
|
442
|
+
node = newNode();
|
|
443
|
+
if (Err) return NULL;
|
|
444
|
+
node->left = left;
|
|
445
|
+
node->right = NULL;
|
|
446
|
+
node->opcode = 9;
|
|
447
|
+
left = node;
|
|
448
|
+
}
|
|
449
|
+
return left;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
//=============================================================================
|
|
453
|
+
|
|
454
|
+
ExprTree* getTree()
|
|
455
|
+
{
|
|
456
|
+
int lex;
|
|
457
|
+
int opcode;
|
|
458
|
+
ExprTree* left;
|
|
459
|
+
ExprTree* right;
|
|
460
|
+
ExprTree* node;
|
|
461
|
+
|
|
462
|
+
left = getOp(&lex);
|
|
463
|
+
for (;;)
|
|
464
|
+
{
|
|
465
|
+
if (lex == 0 || lex == 2)
|
|
466
|
+
{
|
|
467
|
+
if (lex == 2) Bc--;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (lex != 3 && lex != 4)
|
|
472
|
+
{
|
|
473
|
+
Err = 1;
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
opcode = lex;
|
|
478
|
+
right = getOp(&lex);
|
|
479
|
+
node = newNode();
|
|
480
|
+
if (Err) break;
|
|
481
|
+
node->left = left;
|
|
482
|
+
node->right = right;
|
|
483
|
+
node->opcode = opcode;
|
|
484
|
+
left = node;
|
|
485
|
+
}
|
|
486
|
+
return left;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
//=============================================================================
|
|
490
|
+
|
|
491
|
+
void traverseTree(ExprTree* tree, MathExpr** expr)
|
|
492
|
+
// Converts binary tree to linked list (postfix format)
|
|
493
|
+
{
|
|
494
|
+
MathExpr* node;
|
|
495
|
+
if (tree == NULL) return;
|
|
496
|
+
traverseTree(tree->left, expr);
|
|
497
|
+
traverseTree(tree->right, expr);
|
|
498
|
+
node = (MathExpr*)malloc(sizeof(MathExpr));
|
|
499
|
+
if (node)
|
|
500
|
+
{
|
|
501
|
+
node->fvalue = tree->fvalue;
|
|
502
|
+
node->opcode = tree->opcode;
|
|
503
|
+
node->ivar = tree->ivar;
|
|
504
|
+
node->next = NULL;
|
|
505
|
+
node->prev = (*expr);
|
|
506
|
+
}
|
|
507
|
+
if (*expr) (*expr)->next = node;
|
|
508
|
+
(*expr) = node;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
//=============================================================================
|
|
512
|
+
|
|
513
|
+
void deleteTree(ExprTree* tree)
|
|
514
|
+
{
|
|
515
|
+
if (tree)
|
|
516
|
+
{
|
|
517
|
+
if (tree->left) deleteTree(tree->left);
|
|
518
|
+
if (tree->right) deleteTree(tree->right);
|
|
519
|
+
free(tree);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
//=============================================================================
|
|
524
|
+
|
|
525
|
+
// Turn on "precise" floating point option
|
|
526
|
+
#pragma float_control(precise, on, push)
|
|
527
|
+
|
|
528
|
+
double mathexpr_eval(MathExpr* expr, double (*getVariableValue) (int))
|
|
529
|
+
// Mathematica expression evaluation using a stack
|
|
530
|
+
{
|
|
531
|
+
|
|
532
|
+
// --- Note: the exprStack array must be declared locally and not globally
|
|
533
|
+
// since this function can be called recursively.
|
|
534
|
+
|
|
535
|
+
double exprStack[MAX_STACK_SIZE];
|
|
536
|
+
MathExpr* node = expr;
|
|
537
|
+
double r1, r2;
|
|
538
|
+
int stackindex = 0;
|
|
539
|
+
|
|
540
|
+
exprStack[0] = 0.0;
|
|
541
|
+
while (node != NULL)
|
|
542
|
+
{
|
|
543
|
+
switch (node->opcode)
|
|
544
|
+
{
|
|
545
|
+
case 3:
|
|
546
|
+
r1 = exprStack[stackindex];
|
|
547
|
+
stackindex--;
|
|
548
|
+
r2 = exprStack[stackindex];
|
|
549
|
+
exprStack[stackindex] = r2 + r1;
|
|
550
|
+
break;
|
|
551
|
+
|
|
552
|
+
case 4:
|
|
553
|
+
r1 = exprStack[stackindex];
|
|
554
|
+
stackindex--;
|
|
555
|
+
r2 = exprStack[stackindex];
|
|
556
|
+
exprStack[stackindex] = r2 - r1;
|
|
557
|
+
break;
|
|
558
|
+
|
|
559
|
+
case 5:
|
|
560
|
+
r1 = exprStack[stackindex];
|
|
561
|
+
stackindex--;
|
|
562
|
+
r2 = exprStack[stackindex];
|
|
563
|
+
exprStack[stackindex] = r2 * r1;
|
|
564
|
+
break;
|
|
565
|
+
|
|
566
|
+
case 6:
|
|
567
|
+
r1 = exprStack[stackindex];
|
|
568
|
+
stackindex--;
|
|
569
|
+
r2 = exprStack[stackindex];
|
|
570
|
+
exprStack[stackindex] = r2 / r1;
|
|
571
|
+
break;
|
|
572
|
+
|
|
573
|
+
case 7:
|
|
574
|
+
stackindex++;
|
|
575
|
+
exprStack[stackindex] = node->fvalue;
|
|
576
|
+
break;
|
|
577
|
+
|
|
578
|
+
case 8:
|
|
579
|
+
if (getVariableValue != NULL)
|
|
580
|
+
r1 = getVariableValue(node->ivar);
|
|
581
|
+
else r1 = 0.0;
|
|
582
|
+
stackindex++;
|
|
583
|
+
exprStack[stackindex] = r1;
|
|
584
|
+
break;
|
|
585
|
+
|
|
586
|
+
case 9:
|
|
587
|
+
exprStack[stackindex] = -exprStack[stackindex];
|
|
588
|
+
break;
|
|
589
|
+
|
|
590
|
+
case 10:
|
|
591
|
+
r1 = exprStack[stackindex];
|
|
592
|
+
r2 = cos(r1);
|
|
593
|
+
exprStack[stackindex] = r2;
|
|
594
|
+
break;
|
|
595
|
+
|
|
596
|
+
case 11:
|
|
597
|
+
r1 = exprStack[stackindex];
|
|
598
|
+
r2 = sin(r1);
|
|
599
|
+
exprStack[stackindex] = r2;
|
|
600
|
+
break;
|
|
601
|
+
|
|
602
|
+
case 12:
|
|
603
|
+
r1 = exprStack[stackindex];
|
|
604
|
+
r2 = tan(r1);
|
|
605
|
+
exprStack[stackindex] = r2;
|
|
606
|
+
break;
|
|
607
|
+
|
|
608
|
+
case 13:
|
|
609
|
+
r1 = exprStack[stackindex];
|
|
610
|
+
r2 = 1.0 / tan(r1);
|
|
611
|
+
exprStack[stackindex] = r2;
|
|
612
|
+
break;
|
|
613
|
+
|
|
614
|
+
case 14:
|
|
615
|
+
r1 = exprStack[stackindex];
|
|
616
|
+
r2 = fabs(r1);
|
|
617
|
+
exprStack[stackindex] = r2;
|
|
618
|
+
break;
|
|
619
|
+
|
|
620
|
+
case 15:
|
|
621
|
+
r1 = exprStack[stackindex];
|
|
622
|
+
if (r1 < 0.0) r2 = -1.0;
|
|
623
|
+
else if (r1 > 0.0) r2 = 1.0;
|
|
624
|
+
else r2 = 0.0;
|
|
625
|
+
exprStack[stackindex] = r2;
|
|
626
|
+
break;
|
|
627
|
+
|
|
628
|
+
case 16:
|
|
629
|
+
r1 = exprStack[stackindex];
|
|
630
|
+
r2 = sqrt(r1);
|
|
631
|
+
exprStack[stackindex] = r2;
|
|
632
|
+
break;
|
|
633
|
+
|
|
634
|
+
case 17:
|
|
635
|
+
r1 = exprStack[stackindex];
|
|
636
|
+
r2 = log(r1);
|
|
637
|
+
exprStack[stackindex] = r2;
|
|
638
|
+
break;
|
|
639
|
+
|
|
640
|
+
case 18:
|
|
641
|
+
r1 = exprStack[stackindex];
|
|
642
|
+
r2 = exp(r1);
|
|
643
|
+
exprStack[stackindex] = r2;
|
|
644
|
+
break;
|
|
645
|
+
|
|
646
|
+
case 19:
|
|
647
|
+
r1 = exprStack[stackindex];
|
|
648
|
+
r2 = asin(r1);
|
|
649
|
+
exprStack[stackindex] = r2;
|
|
650
|
+
break;
|
|
651
|
+
|
|
652
|
+
case 20:
|
|
653
|
+
r1 = exprStack[stackindex];
|
|
654
|
+
r2 = acos(r1);
|
|
655
|
+
exprStack[stackindex] = r2;
|
|
656
|
+
break;
|
|
657
|
+
|
|
658
|
+
case 21:
|
|
659
|
+
r1 = exprStack[stackindex];
|
|
660
|
+
r2 = atan(r1);
|
|
661
|
+
exprStack[stackindex] = r2;
|
|
662
|
+
break;
|
|
663
|
+
|
|
664
|
+
case 22:
|
|
665
|
+
r1 = exprStack[stackindex];
|
|
666
|
+
r2 = 1.57079632679489661923 - atan(r1);
|
|
667
|
+
exprStack[stackindex] = r2;
|
|
668
|
+
break;
|
|
669
|
+
|
|
670
|
+
case 23:
|
|
671
|
+
r1 = exprStack[stackindex];
|
|
672
|
+
r2 = (exp(r1) - exp(-r1)) / 2.0;
|
|
673
|
+
exprStack[stackindex] = r2;
|
|
674
|
+
break;
|
|
675
|
+
|
|
676
|
+
case 24:
|
|
677
|
+
r1 = exprStack[stackindex];
|
|
678
|
+
r2 = (exp(r1) + exp(-r1)) / 2.0;
|
|
679
|
+
exprStack[stackindex] = r2;
|
|
680
|
+
break;
|
|
681
|
+
|
|
682
|
+
case 25:
|
|
683
|
+
r1 = exprStack[stackindex];
|
|
684
|
+
r2 = (exp(r1) - exp(-r1)) / (exp(r1) + exp(-r1));
|
|
685
|
+
exprStack[stackindex] = r2;
|
|
686
|
+
break;
|
|
687
|
+
|
|
688
|
+
case 26:
|
|
689
|
+
r1 = exprStack[stackindex];
|
|
690
|
+
r2 = (exp(r1) + exp(-r1)) / (exp(r1) - exp(-r1));
|
|
691
|
+
exprStack[stackindex] = r2;
|
|
692
|
+
break;
|
|
693
|
+
|
|
694
|
+
case 27:
|
|
695
|
+
r1 = exprStack[stackindex];
|
|
696
|
+
r2 = log10(r1);
|
|
697
|
+
exprStack[stackindex] = r2;
|
|
698
|
+
break;
|
|
699
|
+
|
|
700
|
+
case 28:
|
|
701
|
+
r1 = exprStack[stackindex];
|
|
702
|
+
if (r1 <= 0.0) r2 = 0.0;
|
|
703
|
+
else r2 = 1.0;
|
|
704
|
+
exprStack[stackindex] = r2;
|
|
705
|
+
break;
|
|
706
|
+
|
|
707
|
+
case 31:
|
|
708
|
+
r1 = exprStack[stackindex];
|
|
709
|
+
stackindex--;
|
|
710
|
+
if (stackindex < 0) break;
|
|
711
|
+
r2 = exprStack[stackindex];
|
|
712
|
+
if (r2 <= 0.0) r2 = 0.0;
|
|
713
|
+
else r2 = pow(r2, r1);
|
|
714
|
+
exprStack[stackindex] = r2;
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
node = node->next;
|
|
718
|
+
}
|
|
719
|
+
if (stackindex >= 0)
|
|
720
|
+
r1 = exprStack[stackindex];
|
|
721
|
+
else
|
|
722
|
+
r1 = 0.0;
|
|
723
|
+
|
|
724
|
+
// Set result to 0 if it is NaN due to an illegal math op
|
|
725
|
+
if (r1 != r1) r1 = 0.0;
|
|
726
|
+
|
|
727
|
+
return r1;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Turn off "precise" floating point option
|
|
731
|
+
#pragma float_control(pop)
|
|
732
|
+
|
|
733
|
+
//=============================================================================
|
|
734
|
+
|
|
735
|
+
void mathexpr_delete(MathExpr* expr)
|
|
736
|
+
{
|
|
737
|
+
if (expr) mathexpr_delete(expr->next);
|
|
738
|
+
free(expr);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
//=============================================================================
|
|
742
|
+
|
|
743
|
+
MathExpr* mathexpr_create(char* formula, int (*getVar) (char*))
|
|
744
|
+
{
|
|
745
|
+
ExprTree* tree;
|
|
746
|
+
MathExpr* expr = NULL;
|
|
747
|
+
MathExpr* result = NULL;
|
|
748
|
+
getVariableIndex = getVar;
|
|
749
|
+
Err = 0;
|
|
750
|
+
PrevLex = 0;
|
|
751
|
+
CurLex = 0;
|
|
752
|
+
S = formula;
|
|
753
|
+
Len = (int)strlen(S);
|
|
754
|
+
Pos = 0;
|
|
755
|
+
Bc = 0;
|
|
756
|
+
tree = getTree();
|
|
757
|
+
if (Bc == 0 && Err == 0)
|
|
758
|
+
{
|
|
759
|
+
traverseTree(tree, &expr);
|
|
760
|
+
while (expr)
|
|
761
|
+
{
|
|
762
|
+
result = expr;
|
|
763
|
+
expr = expr->prev;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
deleteTree(tree);
|
|
767
|
+
return result;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
//=============================================================================
|
|
772
|
+
|
|
773
|
+
char* mathexpr_getStr(MathExpr* expr, char* exprStr,
|
|
774
|
+
char* (*getVariableStr) (int, char*))
|
|
775
|
+
{
|
|
776
|
+
Term TermStack[50];
|
|
777
|
+
MathExpr* node = expr;
|
|
778
|
+
char r1[MAX_TERM_SIZE], r2[MAX_TERM_SIZE];
|
|
779
|
+
int stackindex = 0;
|
|
780
|
+
|
|
781
|
+
strcpy(TermStack[0].s, "");
|
|
782
|
+
while (node != NULL)
|
|
783
|
+
{
|
|
784
|
+
switch (node->opcode)
|
|
785
|
+
{
|
|
786
|
+
case 3:
|
|
787
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
788
|
+
stackindex--;
|
|
789
|
+
strcpy(r2, TermStack[stackindex].s);
|
|
790
|
+
sprintf(TermStack[stackindex].s, "(%s) + (%s)", r2, r1);
|
|
791
|
+
break;
|
|
792
|
+
|
|
793
|
+
case 4:
|
|
794
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
795
|
+
stackindex--;
|
|
796
|
+
strcpy(r2, TermStack[stackindex].s);
|
|
797
|
+
sprintf(TermStack[stackindex].s, "(%s) - (%s)", r2, r1);
|
|
798
|
+
break;
|
|
799
|
+
|
|
800
|
+
case 5:
|
|
801
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
802
|
+
stackindex--;
|
|
803
|
+
strcpy(r2, TermStack[stackindex].s);
|
|
804
|
+
sprintf(TermStack[stackindex].s, "(%s) * (%s)", r2, r1);
|
|
805
|
+
break;
|
|
806
|
+
|
|
807
|
+
case 6:
|
|
808
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
809
|
+
stackindex--;
|
|
810
|
+
strcpy(r2, TermStack[stackindex].s);
|
|
811
|
+
sprintf(TermStack[stackindex].s, "(%s) / (%s)", r2, r1);
|
|
812
|
+
break;
|
|
813
|
+
|
|
814
|
+
case 7:
|
|
815
|
+
stackindex++;
|
|
816
|
+
sprintf(TermStack[stackindex].s, "%.6g", node->fvalue);
|
|
817
|
+
break;
|
|
818
|
+
|
|
819
|
+
case 8:
|
|
820
|
+
if (getVariableStr != NULL)strcpy(r1, getVariableStr(node->ivar, r2));
|
|
821
|
+
else strcpy(r1, "");
|
|
822
|
+
stackindex++;
|
|
823
|
+
strcpy(TermStack[stackindex].s, r1);
|
|
824
|
+
break;
|
|
825
|
+
|
|
826
|
+
case 9:
|
|
827
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
828
|
+
sprintf(TermStack[stackindex].s, "-(%s)", r1);
|
|
829
|
+
break;
|
|
830
|
+
|
|
831
|
+
case 10:
|
|
832
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
833
|
+
sprintf(TermStack[stackindex].s, "cos(%s)", r1);
|
|
834
|
+
break;
|
|
835
|
+
|
|
836
|
+
case 11:
|
|
837
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
838
|
+
sprintf(TermStack[stackindex].s, "sin(%s)", r1);
|
|
839
|
+
break;
|
|
840
|
+
|
|
841
|
+
case 12:
|
|
842
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
843
|
+
sprintf(TermStack[stackindex].s, "tan(%s)", r1);
|
|
844
|
+
break;
|
|
845
|
+
|
|
846
|
+
case 13:
|
|
847
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
848
|
+
sprintf(TermStack[stackindex].s, "cot(%s)", r1);
|
|
849
|
+
break;
|
|
850
|
+
|
|
851
|
+
case 14:
|
|
852
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
853
|
+
sprintf(TermStack[stackindex].s, "abs(%s)", r1);
|
|
854
|
+
break;
|
|
855
|
+
|
|
856
|
+
case 15:
|
|
857
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
858
|
+
sprintf(TermStack[stackindex].s, "sgn(%s)", r1);
|
|
859
|
+
break;
|
|
860
|
+
|
|
861
|
+
case 16:
|
|
862
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
863
|
+
sprintf(TermStack[stackindex].s, "sqrt(%s)", r1);
|
|
864
|
+
break;
|
|
865
|
+
|
|
866
|
+
case 17:
|
|
867
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
868
|
+
sprintf(TermStack[stackindex].s, "log(%s)", r1);
|
|
869
|
+
break;
|
|
870
|
+
|
|
871
|
+
case 18:
|
|
872
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
873
|
+
sprintf(TermStack[stackindex].s, "exp(%s)", r1);
|
|
874
|
+
break;
|
|
875
|
+
|
|
876
|
+
case 19:
|
|
877
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
878
|
+
sprintf(TermStack[stackindex].s, "asin(%s)", r1);
|
|
879
|
+
break;
|
|
880
|
+
|
|
881
|
+
case 20:
|
|
882
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
883
|
+
sprintf(TermStack[stackindex].s, "acos(%s)", r1);
|
|
884
|
+
break;
|
|
885
|
+
|
|
886
|
+
case 21:
|
|
887
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
888
|
+
sprintf(TermStack[stackindex].s, "atan(%s)", r1);
|
|
889
|
+
break;
|
|
890
|
+
|
|
891
|
+
case 22:
|
|
892
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
893
|
+
sprintf(TermStack[stackindex].s, "acot(%s)", r1);
|
|
894
|
+
break;
|
|
895
|
+
|
|
896
|
+
case 23:
|
|
897
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
898
|
+
sprintf(TermStack[stackindex].s, "sinh(%s)", r1);
|
|
899
|
+
break;
|
|
900
|
+
|
|
901
|
+
case 24:
|
|
902
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
903
|
+
sprintf(TermStack[stackindex].s, "cosh(%s)", r1);
|
|
904
|
+
break;
|
|
905
|
+
|
|
906
|
+
case 25:
|
|
907
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
908
|
+
sprintf(TermStack[stackindex].s, "tanh(%s)", r1);
|
|
909
|
+
break;
|
|
910
|
+
|
|
911
|
+
case 26:
|
|
912
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
913
|
+
sprintf(TermStack[stackindex].s, "coth(%s)", r1);
|
|
914
|
+
break;
|
|
915
|
+
|
|
916
|
+
case 27:
|
|
917
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
918
|
+
sprintf(TermStack[stackindex].s, "log10(%s)", r1);
|
|
919
|
+
break;
|
|
920
|
+
|
|
921
|
+
case 28:
|
|
922
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
923
|
+
sprintf(TermStack[stackindex].s, "step(%s)", r1);
|
|
924
|
+
break;
|
|
925
|
+
|
|
926
|
+
case 31:
|
|
927
|
+
strcpy(r1, TermStack[stackindex].s);
|
|
928
|
+
strcpy(r2, TermStack[stackindex - 1].s);
|
|
929
|
+
sprintf(TermStack[stackindex - 1].s, "pow(%s,%s)", r2, r1);
|
|
930
|
+
stackindex--;
|
|
931
|
+
break;
|
|
932
|
+
}
|
|
933
|
+
node = node->next;
|
|
934
|
+
}
|
|
935
|
+
strcpy(exprStr, TermStack[stackindex].s);
|
|
936
|
+
return exprStr;
|
|
937
|
+
}
|