diff options
Diffstat (limited to 'tkblt/generic/tkbltVecMath.C')
-rw-r--r-- | tkblt/generic/tkbltVecMath.C | 1612 |
1 files changed, 0 insertions, 1612 deletions
diff --git a/tkblt/generic/tkbltVecMath.C b/tkblt/generic/tkbltVecMath.C deleted file mode 100644 index 03277d4..0000000 --- a/tkblt/generic/tkbltVecMath.C +++ /dev/null @@ -1,1612 +0,0 @@ -/* - * Smithsonian Astrophysical Observatory, Cambridge, MA, USA - * This code has been modified under the terms listed below and is made - * available under the same terms. - */ - -/* - * Copyright 1995-2004 George A Howlett. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS - * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <cmath> - -#include <float.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <cmath> - -#include "tkbltInt.h" -#include "tkbltVecInt.h" -#include "tkbltNsUtil.h" -#include "tkbltParse.h" - -using namespace std; -using namespace Blt; - -/* - * Three types of math functions: - * - * ComponentProc Function is applied in multiple calls to - * each component of the vector. - * VectorProc Entire vector is passed, each component is - * modified. - * ScalarProc Entire vector is passed, single scalar value - * is returned. - */ - -typedef double (ComponentProc)(double value); -typedef int (VectorProc)(Vector *vPtr); -typedef double (ScalarProc)(Vector *vPtr); - -/* - * Built-in math functions: - */ -typedef int (GenericMathProc) (void*, Tcl_Interp*, Vector*); - -/* - * MathFunction -- - * - * Contains information about math functions that can be called - * for vectors. The table of math functions is global within the - * application. So you can't define two different "sqrt" - * functions. - */ -typedef struct { - const char *name; /* Name of built-in math function. If - * NULL, indicates that the function - * was user-defined and dynamically - * allocated. Function names are - * global across all interpreters. */ - - void *proc; /* Procedure that implements this math - * function. */ - - ClientData clientData; /* Argument to pass when invoking the - * function. */ - -} MathFunction; - -/* The data structure below is used to describe an expression value, - * which can be either a double-precision floating-point value, or a - * string. A given number has only one value at a time. */ - -#define STATIC_STRING_SPACE 150 - -/* - * Tokens -- - * - * The token types are defined below. In addition, there is a - * table associating a precedence with each operator. The order - * of types is important. Consult the code before changing it. - */ -enum Tokens { - VALUE, OPEN_PAREN, CLOSE_PAREN, COMMA, END, UNKNOWN, - MULT = 8, DIVIDE, MOD, PLUS, MINUS, - LEFT_SHIFT, RIGHT_SHIFT, - LESS, GREATER, LEQ, GEQ, EQUAL, NEQ, - OLD_BIT_AND, EXPONENT, OLD_BIT_OR, OLD_QUESTY, OLD_COLON, - AND, OR, UNARY_MINUS, OLD_UNARY_PLUS, NOT, OLD_BIT_NOT -}; - -typedef struct { - Vector *vPtr; - char staticSpace[STATIC_STRING_SPACE]; - ParseValue pv; /* Used to hold a string value, if any. */ -} Value; - -/* - * ParseInfo -- - * - * The data structure below describes the state of parsing an - * expression. It's passed among the routines in this module. - */ -typedef struct { - const char *expr; /* The entire right-hand side of the - * expression, as originally passed to - * Blt_ExprVector. */ - - const char *nextPtr; /* Position of the next character to - * be scanned from the expression - * string. */ - - enum Tokens token; /* Type of the last token to be parsed - * from nextPtr. See below for - * definitions. Corresponds to the - * characters just before nextPtr. */ - -} ParseInfo; - -/* - * Precedence table. The values for non-operator token types are ignored. - */ -static int precTable[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, - 12, 12, 12, /* MULT, DIVIDE, MOD */ - 11, 11, /* PLUS, MINUS */ - 10, 10, /* LEFT_SHIFT, RIGHT_SHIFT */ - 9, 9, 9, 9, /* LESS, GREATER, LEQ, GEQ */ - 8, 8, /* EQUAL, NEQ */ - 7, /* OLD_BIT_AND */ - 13, /* EXPONENTIATION */ - 5, /* OLD_BIT_OR */ - 4, /* AND */ - 3, /* OR */ - 2, /* OLD_QUESTY */ - 1, /* OLD_COLON */ - 14, 14, 14, 14 /* UNARY_MINUS, OLD_UNARY_PLUS, NOT, - * OLD_BIT_NOT */ - }; - - -/* - * Forward declarations. - */ - -static int NextValue(Tcl_Interp* interp, ParseInfo *piPtr, int prec, - Value *valuePtr); - -static int Sort(Vector *vPtr) -{ - size_t* map = Vec_SortMap(&vPtr, 1); - double* values = (double*)malloc(sizeof(double) * vPtr->length); - for(int ii = vPtr->first; ii <= vPtr->last; ii++) - values[ii] = vPtr->valueArr[map[ii]]; - - free(map); - for (int ii = vPtr->first; ii <= vPtr->last; ii++) - vPtr->valueArr[ii] = values[ii]; - - free(values); - return TCL_OK; -} - -static double Length(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - return (double)(vPtr->last - vPtr->first + 1); -} - -double Blt_VecMax(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - return Vec_Max(vPtr); -} - -double Blt_VecMin(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - return Vec_Min(vPtr); -} - -int Blt_ExprVector(Tcl_Interp* interp, char *string, Blt_Vector *vector) -{ - return ExprVector(interp,string,vector); -} - -static double Product(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double prod; - double *vp, *vend; - - prod = 1.0; - for(vp = vPtr->valueArr + vPtr->first, - vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { - prod *= *vp; - } - return prod; -} - -static double Sum(Blt_Vector *vectorPtr) -{ - // Kahan summation algorithm - - Vector *vPtr = (Vector *)vectorPtr; - double* vp = vPtr->valueArr + vPtr->first; - double sum = *vp++; - double c = 0.0; /* A running compensation for lost - * low-order bits.*/ - for (double* vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { - double y = *vp - c; /* So far, so good: c is zero.*/ - double t = sum + y; /* Alas, sum is big, y small, so - * low-order digits of y are lost.*/ - c = (t - sum) - y; /* (t - sum) recovers the high-order - * part of y; subtracting y recovers - * -(low part of y) */ - sum = t; - } - - return sum; -} - -static double Mean(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double sum = Sum(vectorPtr); - int n = vPtr->last - vPtr->first + 1; - - return sum / (double)n; -} - -// var = 1/N Sum( (x[i] - mean)^2 ) -static double Variance(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double mean = Mean(vectorPtr); - double var = 0.0; - int count = 0; - for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; - vp <= vend; vp++) { - double dx = *vp - mean; - var += dx * dx; - count++; - } - - if (count < 2) - return 0.0; - - var /= (double)(count - 1); - return var; -} - -// skew = Sum( (x[i] - mean)^3 ) / (var^3/2) -static double Skew(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double mean = Mean(vectorPtr); - double var = 0; - double skew = 0; - int count = 0; - for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; - vp <= vend; vp++) { - double diff = *vp - mean; - diff = fabs(diff); - double diffsq = diff * diff; - var += diffsq; - skew += diffsq * diff; - count++; - } - - if (count < 2) - return 0.0; - - var /= (double)(count - 1); - skew /= count * var * sqrt(var); - return skew; -} - -static double StdDeviation(Blt_Vector *vectorPtr) -{ - double var; - - var = Variance(vectorPtr); - if (var > 0.0) { - return sqrt(var); - } - return 0.0; -} - -static double AvgDeviation(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double mean = Mean(vectorPtr); - double avg = 0.0; - int count = 0; - for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; - vp <= vend; vp++) { - double diff = *vp - mean; - avg += fabs(diff); - count++; - } - - if (count < 2) - return 0.0; - - avg /= (double)count; - return avg; -} - -static double Kurtosis(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double mean = Mean(vectorPtr); - double var = 0; - double kurt = 0; - int count = 0; - for(double *vp=vPtr->valueArr+vPtr->first, *vend=vPtr->valueArr+vPtr->last; - vp <= vend; vp++) { - double diff = *vp - mean; - double diffsq = diff * diff; - var += diffsq; - kurt += diffsq * diffsq; - count++; - } - - if (count < 2) - return 0.0; - - var /= (double)(count - 1); - - if (var == 0.0) - return 0.0; - - kurt /= (count * var * var); - return kurt - 3.0; /* Fisher Kurtosis */ -} - -static double Median(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - size_t *map; - double q2; - int mid; - - if (vPtr->length == 0) { - return -DBL_MAX; - } - map = Vec_SortMap(&vPtr, 1); - mid = (vPtr->length - 1) / 2; - - /* - * Determine Q2 by checking if the number of elements [0..n-1] is - * odd or even. If even, we must take the average of the two - * middle values. - */ - if (vPtr->length & 1) { /* Odd */ - q2 = vPtr->valueArr[map[mid]]; - } else { /* Even */ - q2 = (vPtr->valueArr[map[mid]] + - vPtr->valueArr[map[mid + 1]]) * 0.5; - } - free(map); - return q2; -} - -static double Q1(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double q1; - size_t *map; - - if (vPtr->length == 0) { - return -DBL_MAX; - } - map = Vec_SortMap(&vPtr, 1); - - if (vPtr->length < 4) { - q1 = vPtr->valueArr[map[0]]; - } else { - int mid, q; - - mid = (vPtr->length - 1) / 2; - q = mid / 2; - - /* - * Determine Q1 by checking if the number of elements in the - * bottom half [0..mid) is odd or even. If even, we must - * take the average of the two middle values. - */ - if (mid & 1) { /* Odd */ - q1 = vPtr->valueArr[map[q]]; - } else { /* Even */ - q1 = (vPtr->valueArr[map[q]] + - vPtr->valueArr[map[q + 1]]) * 0.5; - } - } - free(map); - return q1; -} - -static double Q3(Blt_Vector *vectorPtr) -{ - Vector *vPtr = (Vector *)vectorPtr; - double q3; - size_t *map; - - if (vPtr->length == 0) { - return -DBL_MAX; - } - - map = Vec_SortMap(&vPtr, 1); - - if (vPtr->length < 4) { - q3 = vPtr->valueArr[map[vPtr->length - 1]]; - } else { - int mid, q; - - mid = (vPtr->length - 1) / 2; - q = (vPtr->length + mid) / 2; - - /* - * Determine Q3 by checking if the number of elements in the - * upper half (mid..n-1] is odd or even. If even, we must - * take the average of the two middle values. - */ - if (mid & 1) { /* Odd */ - q3 = vPtr->valueArr[map[q]]; - } else { /* Even */ - q3 = (vPtr->valueArr[map[q]] + - vPtr->valueArr[map[q + 1]]) * 0.5; - } - } - free(map); - return q3; -} - -static int Norm(Blt_Vector *vector) -{ - Vector *vPtr = (Vector *)vector; - double norm, range, min, max; - int i; - - min = Vec_Min(vPtr); - max = Vec_Max(vPtr); - range = max - min; - for (i = 0; i < vPtr->length; i++) { - norm = (vPtr->valueArr[i] - min) / range; - vPtr->valueArr[i] = norm; - } - return TCL_OK; -} - -static double Nonzeros(Blt_Vector *vector) -{ - Vector *vPtr = (Vector *)vector; - int count; - double *vp, *vend; - - count = 0; - for(vp = vPtr->valueArr + vPtr->first, vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { - if (*vp == 0.0) - count++; - } - return (double) count; -} - -static double Fabs(double value) -{ - if (value < 0.0) - return -value; - return value; -} - -static double Round(double value) -{ - if (value < 0.0) - return ceil(value - 0.5); - else - return floor(value + 0.5); -} - -static double Fmod(double x, double y) -{ - if (y == 0.0) - return 0.0; - return x - (floor(x / y) * y); -} - -/* - *--------------------------------------------------------------------------- - * - * MathError -- - * - * This procedure is called when an error occurs during a - * floating-point operation. It reads errno and sets - * interp->result accordingly. - * - * Results: - * Interp->result is set to hold an error message. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ -static void MathError(Tcl_Interp* interp, double value) -{ - if ((errno == EDOM) || (value != value)) { - Tcl_AppendResult(interp, "domain error: argument not in valid range", - (char *)NULL); - Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", - Tcl_GetStringResult(interp), (char *)NULL); - } - else if ((errno == ERANGE) || isinf(value)) { - if (value == 0.0) { - Tcl_AppendResult(interp, - "floating-point value too small to represent", - (char *)NULL); - Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", - Tcl_GetStringResult(interp), (char *)NULL); - } - else { - Tcl_AppendResult(interp, - "floating-point value too large to represent", - (char *)NULL); - Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", - Tcl_GetStringResult(interp), (char *)NULL); - } - } - else { - Tcl_AppendResult(interp, "unknown floating-point error, ", - "errno = ", Itoa(errno), (char *)NULL); - Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", - Tcl_GetStringResult(interp), (char *)NULL); - } -} - -static int ParseString(Tcl_Interp* interp, const char *string, Value *valuePtr) -{ - const char *endPtr; - double value; - - errno = 0; - - /* - * The string can be either a number or a vector. First try to - * convert the string to a number. If that fails then see if - * we can find a vector by that name. - */ - - value = strtod(string, (char **)&endPtr); - if ((endPtr != string) && (*endPtr == '\0')) { - if (errno != 0) { - Tcl_ResetResult(interp); - MathError(interp, value); - return TCL_ERROR; - } - /* Numbers are stored as single element vectors. */ - if (Vec_ChangeLength(interp, valuePtr->vPtr, 1) != TCL_OK) { - return TCL_ERROR; - } - valuePtr->vPtr->valueArr[0] = value; - return TCL_OK; - } else { - Vector *vPtr; - - while (isspace((unsigned char)(*string))) { - string++; /* Skip spaces leading the vector name. */ - } - vPtr = Vec_ParseElement(interp, valuePtr->vPtr->dataPtr, - string, &endPtr, NS_SEARCH_BOTH); - if (vPtr == NULL) { - return TCL_ERROR; - } - if (*endPtr != '\0') { - Tcl_AppendResult(interp, "extra characters after vector", - (char *)NULL); - return TCL_ERROR; - } - /* Copy the designated vector to our temporary. */ - Vec_Duplicate(valuePtr->vPtr, vPtr); - } - return TCL_OK; -} - -static int ParseMathFunction(Tcl_Interp* interp, const char *start, - ParseInfo *piPtr, Value *valuePtr) -{ - Tcl_HashEntry *hPtr; - MathFunction *mathPtr; /* Info about math function. */ - char *p; - VectorInterpData *dataPtr; /* Interpreter-specific data. */ - GenericMathProc *proc; - - /* - * Find the end of the math function's name and lookup the - * record for the function. - */ - p = (char *)start; - while (isspace((unsigned char)(*p))) { - p++; - } - piPtr->nextPtr = p; - while (isalnum((unsigned char)(*p)) || (*p == '_')) { - p++; - } - if (*p != '(') { - return TCL_RETURN; /* Must start with open parenthesis */ - } - dataPtr = valuePtr->vPtr->dataPtr; - *p = '\0'; - hPtr = Tcl_FindHashEntry(&dataPtr->mathProcTable, piPtr->nextPtr); - *p = '('; - if (hPtr == NULL) { - return TCL_RETURN; /* Name doesn't match any known function */ - } - /* Pick up the single value as the argument to the function */ - piPtr->token = OPEN_PAREN; - piPtr->nextPtr = p + 1; - valuePtr->pv.next = valuePtr->pv.buffer; - if (NextValue(interp, piPtr, -1, valuePtr) != TCL_OK) { - return TCL_ERROR; /* Parse error */ - } - if (piPtr->token != CLOSE_PAREN) { - Tcl_AppendResult(interp, "unmatched parentheses in expression \"", - piPtr->expr, "\"", (char *)NULL); - return TCL_ERROR; /* Missing right parenthesis */ - } - mathPtr = (MathFunction*)Tcl_GetHashValue(hPtr); - proc = (GenericMathProc*)mathPtr->proc; - if ((*proc) (mathPtr->clientData, interp, valuePtr->vPtr) != TCL_OK) { - return TCL_ERROR; /* Function invocation error */ - } - piPtr->token = VALUE; - return TCL_OK; -} - -static int NextToken(Tcl_Interp* interp, ParseInfo *piPtr, Value *valuePtr) -{ - const char *p; - const char *endPtr; - const char *var; - int result; - - p = piPtr->nextPtr; - while (isspace((unsigned char)(*p))) { - p++; - } - if (*p == '\0') { - piPtr->token = END; - piPtr->nextPtr = p; - return TCL_OK; - } - /* - * Try to parse the token as a floating-point number. But check - * that the first character isn't a "-" or "+", which "strtod" - * will happily accept as an unary operator. Otherwise, we might - * accidently treat a binary operator as unary by mistake, which - * will eventually cause a syntax error. - */ - if ((*p != '-') && (*p != '+')) { - double value; - - errno = 0; - value = strtod(p, (char **)&endPtr); - if (endPtr != p) { - if (errno != 0) { - MathError(interp, value); - return TCL_ERROR; - } - piPtr->token = VALUE; - piPtr->nextPtr = endPtr; - - /* - * Save the single floating-point value as an 1-component vector. - */ - if (Vec_ChangeLength(interp, valuePtr->vPtr, 1) != TCL_OK) { - return TCL_ERROR; - } - valuePtr->vPtr->valueArr[0] = value; - return TCL_OK; - } - } - piPtr->nextPtr = p + 1; - switch (*p) { - case '$': - piPtr->token = VALUE; - var = Tcl_ParseVar(interp, p, &endPtr); - if (var == NULL) { - return TCL_ERROR; - } - piPtr->nextPtr = endPtr; - Tcl_ResetResult(interp); - result = ParseString(interp, var, valuePtr); - return result; - - case '[': - piPtr->token = VALUE; - result = ParseNestedCmd(interp, p + 1, 0, &endPtr, &valuePtr->pv); - if (result != TCL_OK) { - return result; - } - piPtr->nextPtr = endPtr; - Tcl_ResetResult(interp); - result = ParseString(interp, valuePtr->pv.buffer, valuePtr); - return result; - - case '"': - piPtr->token = VALUE; - result = ParseQuotes(interp, p + 1, '"', 0, &endPtr, &valuePtr->pv); - if (result != TCL_OK) { - return result; - } - piPtr->nextPtr = endPtr; - Tcl_ResetResult(interp); - result = ParseString(interp, valuePtr->pv.buffer, valuePtr); - return result; - - case '{': - piPtr->token = VALUE; - result = ParseBraces(interp, p + 1, &endPtr, &valuePtr->pv); - if (result != TCL_OK) { - return result; - } - piPtr->nextPtr = endPtr; - Tcl_ResetResult(interp); - result = ParseString(interp, valuePtr->pv.buffer, valuePtr); - return result; - - case '(': - piPtr->token = OPEN_PAREN; - break; - - case ')': - piPtr->token = CLOSE_PAREN; - break; - - case ',': - piPtr->token = COMMA; - break; - - case '*': - piPtr->token = MULT; - break; - - case '/': - piPtr->token = DIVIDE; - break; - - case '%': - piPtr->token = MOD; - break; - - case '+': - piPtr->token = PLUS; - break; - - case '-': - piPtr->token = MINUS; - break; - - case '^': - piPtr->token = EXPONENT; - break; - - case '<': - switch (*(p + 1)) { - case '<': - piPtr->nextPtr = p + 2; - piPtr->token = LEFT_SHIFT; - break; - case '=': - piPtr->nextPtr = p + 2; - piPtr->token = LEQ; - break; - default: - piPtr->token = LESS; - break; - } - break; - - case '>': - switch (*(p + 1)) { - case '>': - piPtr->nextPtr = p + 2; - piPtr->token = RIGHT_SHIFT; - break; - case '=': - piPtr->nextPtr = p + 2; - piPtr->token = GEQ; - break; - default: - piPtr->token = GREATER; - break; - } - break; - - case '=': - if (*(p + 1) == '=') { - piPtr->nextPtr = p + 2; - piPtr->token = EQUAL; - } else { - piPtr->token = UNKNOWN; - } - break; - - case '&': - if (*(p + 1) == '&') { - piPtr->nextPtr = p + 2; - piPtr->token = AND; - } else { - piPtr->token = UNKNOWN; - } - break; - - case '|': - if (*(p + 1) == '|') { - piPtr->nextPtr = p + 2; - piPtr->token = OR; - } else { - piPtr->token = UNKNOWN; - } - break; - - case '!': - if (*(p + 1) == '=') { - piPtr->nextPtr = p + 2; - piPtr->token = NEQ; - } else { - piPtr->token = NOT; - } - break; - - default: - piPtr->token = VALUE; - result = ParseMathFunction(interp, p, piPtr, valuePtr); - if ((result == TCL_OK) || (result == TCL_ERROR)) { - return result; - } else { - Vector *vPtr; - - while (isspace((unsigned char)(*p))) { - p++; /* Skip spaces leading the vector name. */ - } - vPtr = Vec_ParseElement(interp, valuePtr->vPtr->dataPtr, - p, &endPtr, NS_SEARCH_BOTH); - if (vPtr == NULL) { - return TCL_ERROR; - } - Vec_Duplicate(valuePtr->vPtr, vPtr); - piPtr->nextPtr = endPtr; - } - } - return TCL_OK; -} - -static int NextValue(Tcl_Interp* interp, ParseInfo *piPtr, - int prec, Value *valuePtr) -{ - Value value2; /* Second operand for current operator. */ - int oper; /* Current operator (either unary or binary). */ - int gotOp; /* Non-zero means already lexed the operator - * (while picking up value for unary operator). - * Don't lex again. */ - int result; - Vector *vPtr, *v2Ptr; - int i; - - /* - * There are two phases to this procedure. First, pick off an initial - * value. Then, parse (binary operator, value) pairs until done. - */ - - vPtr = valuePtr->vPtr; - v2Ptr = Vec_New(vPtr->dataPtr); - gotOp = 0; - value2.vPtr = v2Ptr; - value2.pv.buffer = value2.pv.next = value2.staticSpace; - value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1; - value2.pv.expandProc = ExpandParseValue; - value2.pv.clientData = NULL; - - result = NextToken(interp, piPtr, valuePtr); - if (result != TCL_OK) { - goto done; - } - if (piPtr->token == OPEN_PAREN) { - - /* Parenthesized sub-expression. */ - - result = NextValue(interp, piPtr, -1, valuePtr); - if (result != TCL_OK) { - goto done; - } - if (piPtr->token != CLOSE_PAREN) { - Tcl_AppendResult(interp, "unmatched parentheses in expression \"", - piPtr->expr, "\"", (char *)NULL); - result = TCL_ERROR; - goto done; - } - } else { - if (piPtr->token == MINUS) { - piPtr->token = UNARY_MINUS; - } - if (piPtr->token >= UNARY_MINUS) { - oper = piPtr->token; - result = NextValue(interp, piPtr, precTable[oper], valuePtr); - if (result != TCL_OK) { - goto done; - } - gotOp = 1; - /* Process unary operators. */ - switch (oper) { - case UNARY_MINUS: - for(i = 0; i < vPtr->length; i++) { - vPtr->valueArr[i] = -(vPtr->valueArr[i]); - } - break; - - case NOT: - for(i = 0; i < vPtr->length; i++) { - vPtr->valueArr[i] = (double)(!vPtr->valueArr[i]); - } - break; - default: - Tcl_AppendResult(interp, "unknown operator", (char *)NULL); - goto error; - } - } else if (piPtr->token != VALUE) { - Tcl_AppendResult(interp, "missing operand", (char *)NULL); - goto error; - } - } - if (!gotOp) { - result = NextToken(interp, piPtr, &value2); - if (result != TCL_OK) { - goto done; - } - } - /* - * Got the first operand. Now fetch (operator, operand) pairs. - */ - for (;;) { - oper = piPtr->token; - - value2.pv.next = value2.pv.buffer; - if ((oper < MULT) || (oper >= UNARY_MINUS)) { - if ((oper == END) || (oper == CLOSE_PAREN) || - (oper == COMMA)) { - result = TCL_OK; - goto done; - } else { - Tcl_AppendResult(interp, "bad operator", (char *)NULL); - goto error; - } - } - if (precTable[oper] <= prec) { - result = TCL_OK; - goto done; - } - result = NextValue(interp, piPtr, precTable[oper], &value2); - if (result != TCL_OK) { - goto done; - } - if ((piPtr->token < MULT) && (piPtr->token != VALUE) && - (piPtr->token != END) && (piPtr->token != CLOSE_PAREN) && - (piPtr->token != COMMA)) { - Tcl_AppendResult(interp, "unexpected token in expression", - (char *)NULL); - goto error; - } - /* - * At this point we have two vectors and an operator. - */ - - if (v2Ptr->length == 1) { - double *opnd; - double scalar; - - /* - * 2nd operand is a scalar. - */ - scalar = v2Ptr->valueArr[0]; - opnd = vPtr->valueArr; - switch (oper) { - case MULT: - for(i = 0; i < vPtr->length; i++) { - opnd[i] *= scalar; - } - break; - - case DIVIDE: - if (scalar == 0.0) { - Tcl_AppendResult(interp, "divide by zero", (char *)NULL); - goto error; - } - for(i = 0; i < vPtr->length; i++) { - opnd[i] /= scalar; - } - break; - - case PLUS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] += scalar; - } - break; - - case MINUS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] -= scalar; - } - break; - - case EXPONENT: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = pow(opnd[i], scalar); - } - break; - - case MOD: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = Fmod(opnd[i], scalar); - } - break; - - case LESS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] < scalar); - } - break; - - case GREATER: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] > scalar); - } - break; - - case LEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] <= scalar); - } - break; - - case GEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] >= scalar); - } - break; - - case EQUAL: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] == scalar); - } - break; - - case NEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] != scalar); - } - break; - - case AND: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] && scalar); - } - break; - - case OR: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] || scalar); - } - break; - - case LEFT_SHIFT: - { - int offset; - - offset = (int)scalar % vPtr->length; - if (offset > 0) { - double *hold; - int j; - - hold = (double*)malloc(sizeof(double) * offset); - for (i = 0; i < offset; i++) { - hold[i] = opnd[i]; - } - for (i = offset, j = 0; i < vPtr->length; i++, j++) { - opnd[j] = opnd[i]; - } - for (i = 0, j = vPtr->length - offset; - j < vPtr->length; i++, j++) { - opnd[j] = hold[i]; - } - free(hold); - } - } - break; - - case RIGHT_SHIFT: - { - int offset; - - offset = (int)scalar % vPtr->length; - if (offset > 0) { - double *hold; - int j; - - hold = (double*)malloc(sizeof(double) * offset); - for (i = vPtr->length - offset, j = 0; - i < vPtr->length; i++, j++) { - hold[j] = opnd[i]; - } - for (i = vPtr->length - offset - 1, - j = vPtr->length - 1; i >= 0; i--, j--) { - opnd[j] = opnd[i]; - } - for (i = 0; i < offset; i++) { - opnd[i] = hold[i]; - } - free(hold); - } - } - break; - - default: - Tcl_AppendResult(interp, "unknown operator in expression", - (char *)NULL); - goto error; - } - - } else if (vPtr->length == 1) { - double *opnd; - double scalar; - - /* - * 1st operand is a scalar. - */ - scalar = vPtr->valueArr[0]; - Vec_Duplicate(vPtr, v2Ptr); - opnd = vPtr->valueArr; - switch (oper) { - case MULT: - for(i = 0; i < vPtr->length; i++) { - opnd[i] *= scalar; - } - break; - - case PLUS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] += scalar; - } - break; - - case DIVIDE: - for(i = 0; i < vPtr->length; i++) { - if (opnd[i] == 0.0) { - Tcl_AppendResult(interp, "divide by zero", - (char *)NULL); - goto error; - } - opnd[i] = (scalar / opnd[i]); - } - break; - - case MINUS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = scalar - opnd[i]; - } - break; - - case EXPONENT: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = pow(scalar, opnd[i]); - } - break; - - case MOD: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = Fmod(scalar, opnd[i]); - } - break; - - case LESS: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(scalar < opnd[i]); - } - break; - - case GREATER: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(scalar > opnd[i]); - } - break; - - case LEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(scalar >= opnd[i]); - } - break; - - case GEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(scalar <= opnd[i]); - } - break; - - case EQUAL: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] == scalar); - } - break; - - case NEQ: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] != scalar); - } - break; - - case AND: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] && scalar); - } - break; - - case OR: - for(i = 0; i < vPtr->length; i++) { - opnd[i] = (double)(opnd[i] || scalar); - } - break; - - case LEFT_SHIFT: - case RIGHT_SHIFT: - Tcl_AppendResult(interp, "second shift operand must be scalar", - (char *)NULL); - goto error; - - default: - Tcl_AppendResult(interp, "unknown operator in expression", - (char *)NULL); - goto error; - } - } else { - double *opnd1, *opnd2; - /* - * Carry out the function of the specified operator. - */ - if (vPtr->length != v2Ptr->length) { - Tcl_AppendResult(interp, "vectors are different lengths", - (char *)NULL); - goto error; - } - opnd1 = vPtr->valueArr, opnd2 = v2Ptr->valueArr; - switch (oper) { - case MULT: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] *= opnd2[i]; - } - break; - - case DIVIDE: - for (i = 0; i < vPtr->length; i++) { - if (opnd2[i] == 0.0) { - Tcl_AppendResult(interp, - "can't divide by 0.0 vector component", - (char *)NULL); - goto error; - } - opnd1[i] /= opnd2[i]; - } - break; - - case PLUS: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] += opnd2[i]; - } - break; - - case MINUS: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] -= opnd2[i]; - } - break; - - case MOD: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = Fmod(opnd1[i], opnd2[i]); - } - break; - - case EXPONENT: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = pow(opnd1[i], opnd2[i]); - } - break; - - case LESS: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] < opnd2[i]); - } - break; - - case GREATER: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] > opnd2[i]); - } - break; - - case LEQ: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] <= opnd2[i]); - } - break; - - case GEQ: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] >= opnd2[i]); - } - break; - - case EQUAL: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] == opnd2[i]); - } - break; - - case NEQ: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] != opnd2[i]); - } - break; - - case AND: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] && opnd2[i]); - } - break; - - case OR: - for (i = 0; i < vPtr->length; i++) { - opnd1[i] = (double)(opnd1[i] || opnd2[i]); - } - break; - - case LEFT_SHIFT: - case RIGHT_SHIFT: - Tcl_AppendResult(interp, "second shift operand must be scalar", - (char *)NULL); - goto error; - - default: - Tcl_AppendResult(interp, "unknown operator in expression", - (char *)NULL); - goto error; - } - } - } - done: - if (value2.pv.buffer != value2.staticSpace) { - free(value2.pv.buffer); - } - Vec_Free(v2Ptr); - return result; - - error: - if (value2.pv.buffer != value2.staticSpace) { - free(value2.pv.buffer); - } - Vec_Free(v2Ptr); - return TCL_ERROR; -} - -static int EvaluateExpression(Tcl_Interp* interp, char *string, - Value *valuePtr) -{ - ParseInfo info; - int result; - Vector *vPtr; - double *vp, *vend; - - info.expr = info.nextPtr = string; - valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->staticSpace; - valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1; - valuePtr->pv.expandProc = ExpandParseValue; - valuePtr->pv.clientData = NULL; - - result = NextValue(interp, &info, -1, valuePtr); - if (result != TCL_OK) { - return result; - } - if (info.token != END) { - Tcl_AppendResult(interp, ": syntax error in expression \"", - string, "\"", (char *)NULL); - return TCL_ERROR; - } - vPtr = valuePtr->vPtr; - - /* Check for NaN's and overflows. */ - for (vp = vPtr->valueArr, vend = vp + vPtr->length; vp < vend; vp++) { - if (!isfinite(*vp)) { - /* - * IEEE floating-point error. - */ - MathError(interp, *vp); - return TCL_ERROR; - } - } - return TCL_OK; -} - -static int ComponentFunc(ClientData clientData, Tcl_Interp* interp, - Vector *vPtr) -{ - ComponentProc *procPtr = (ComponentProc *) clientData; - double *vp, *vend; - - errno = 0; - for(vp = vPtr->valueArr + vPtr->first, - vend = vPtr->valueArr + vPtr->last; vp <= vend; vp++) { - *vp = (*procPtr) (*vp); - if (errno != 0) { - MathError(interp, *vp); - return TCL_ERROR; - } - if (!isfinite(*vp)) { - /* - * IEEE floating-point error. - */ - MathError(interp, *vp); - return TCL_ERROR; - } - } - return TCL_OK; -} - -static int ScalarFunc(ClientData clientData, Tcl_Interp* interp, Vector *vPtr) -{ - double value; - ScalarProc *procPtr = (ScalarProc *) clientData; - - errno = 0; - value = (*procPtr) (vPtr); - if (errno != 0) { - MathError(interp, value); - return TCL_ERROR; - } - if (Vec_ChangeLength(interp, vPtr, 1) != TCL_OK) { - return TCL_ERROR; - } - vPtr->valueArr[0] = value; - return TCL_OK; -} - -static int VectorFunc(ClientData clientData, Tcl_Interp* interp, Vector *vPtr) -{ - VectorProc *procPtr = (VectorProc *) clientData; - - return (*procPtr) (vPtr); -} - - -static MathFunction mathFunctions[] = - { - {"abs", (void*)ComponentFunc, (ClientData)Fabs}, - {"acos", (void*)ComponentFunc, (ClientData)(double (*)(double))acos}, - {"asin", (void*)ComponentFunc, (ClientData)(double (*)(double))asin}, - {"atan", (void*)ComponentFunc, (ClientData)(double (*)(double))atan}, - {"adev", (void*)ScalarFunc, (ClientData)AvgDeviation}, - {"ceil", (void*)ComponentFunc, (ClientData)(double (*)(double))ceil}, - {"cos", (void*)ComponentFunc, (ClientData)(double (*)(double))cos}, - {"cosh", (void*)ComponentFunc, (ClientData)(double (*)(double))cosh}, - {"exp", (void*)ComponentFunc, (ClientData)(double (*)(double))exp}, - {"floor", (void*)ComponentFunc, (ClientData)(double (*)(double))floor}, - {"kurtosis",(void*)ScalarFunc, (ClientData)Kurtosis}, - {"length", (void*)ScalarFunc, (ClientData)Length}, - {"log", (void*)ComponentFunc, (ClientData)(double (*)(double))log}, - {"log10", (void*)ComponentFunc, (ClientData)(double (*)(double))log10}, - {"max", (void*)ScalarFunc, (ClientData)Blt_VecMax}, - {"mean", (void*)ScalarFunc, (ClientData)Mean}, - {"median", (void*)ScalarFunc, (ClientData)Median}, - {"min", (void*)ScalarFunc, (ClientData)Blt_VecMin}, - {"norm", (void*)VectorFunc, (ClientData)Norm}, - {"nz", (void*)ScalarFunc, (ClientData)Nonzeros}, - {"q1", (void*)ScalarFunc, (ClientData)Q1}, - {"q3", (void*)ScalarFunc, (ClientData)Q3}, - {"prod", (void*)ScalarFunc, (ClientData)Product}, - {"random", (void*)ComponentFunc, (ClientData)drand48}, - {"round", (void*)ComponentFunc, (ClientData)Round}, - {"sdev", (void*)ScalarFunc, (ClientData)StdDeviation}, - {"sin", (void*)ComponentFunc, (ClientData)(double (*)(double))sin}, - {"sinh", (void*)ComponentFunc, (ClientData)(double (*)(double))sinh}, - {"skew", (void*)ScalarFunc, (ClientData)Skew}, - {"sort", (void*)VectorFunc, (ClientData)Sort}, - {"sqrt", (void*)ComponentFunc, (ClientData)(double (*)(double))sqrt}, - {"sum", (void*)ScalarFunc, (ClientData)Sum}, - {"tan", (void*)ComponentFunc, (ClientData)(double (*)(double))tan}, - {"tanh", (void*)ComponentFunc, (ClientData)(double (*)(double))tanh}, - {"var", (void*)ScalarFunc, (ClientData)Variance}, - {(char *)NULL,}, - }; - -void Blt::Vec_InstallMathFunctions(Tcl_HashTable *tablePtr) -{ - MathFunction *mathPtr; - - for (mathPtr = mathFunctions; mathPtr->name != NULL; mathPtr++) { - Tcl_HashEntry *hPtr; - int isNew; - - hPtr = Tcl_CreateHashEntry(tablePtr, mathPtr->name, &isNew); - Tcl_SetHashValue(hPtr, (ClientData)mathPtr); - } -} - -void Blt::Vec_UninstallMathFunctions(Tcl_HashTable *tablePtr) -{ - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - - for (hPtr = Tcl_FirstHashEntry(tablePtr, &cursor); hPtr != NULL; - hPtr = Tcl_NextHashEntry(&cursor)) { - MathFunction *mathPtr = (MathFunction*)Tcl_GetHashValue(hPtr); - if (mathPtr->name == NULL) - free(mathPtr); - } -} - -static void InstallIndexProc(Tcl_HashTable *tablePtr, const char *string, - Blt_VectorIndexProc *procPtr) -{ - Tcl_HashEntry *hPtr; - int dummy; - - hPtr = Tcl_CreateHashEntry(tablePtr, string, &dummy); - if (procPtr == NULL) - Tcl_DeleteHashEntry(hPtr); - else - Tcl_SetHashValue(hPtr, (ClientData)procPtr); -} - -void Blt::Vec_InstallSpecialIndices(Tcl_HashTable *tablePtr) -{ - InstallIndexProc(tablePtr, "min", Blt_VecMin); - InstallIndexProc(tablePtr, "max", Blt_VecMax); - InstallIndexProc(tablePtr, "mean", Mean); - InstallIndexProc(tablePtr, "sum", Sum); - InstallIndexProc(tablePtr, "prod", Product); -} - -int Blt::ExprVector(Tcl_Interp* interp, char *string, Blt_Vector *vector) -{ - VectorInterpData *dataPtr; /* Interpreter-specific data. */ - Vector *vPtr = (Vector *)vector; - Value value; - - dataPtr = (vector != NULL) ? vPtr->dataPtr : Vec_GetInterpData(interp); - value.vPtr = Vec_New(dataPtr); - if (EvaluateExpression(interp, string, &value) != TCL_OK) { - Vec_Free(value.vPtr); - return TCL_ERROR; - } - if (vPtr != NULL) { - Vec_Duplicate(vPtr, value.vPtr); - } else { - Tcl_Obj *listObjPtr; - double *vp, *vend; - - /* No result vector. Put values in interp->result. */ - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - for (vp = value.vPtr->valueArr, vend = vp + value.vPtr->length; - vp < vend; vp++) { - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(*vp)); - } - Tcl_SetObjResult(interp, listObjPtr); - } - Vec_Free(value.vPtr); - return TCL_OK; -} - -#ifdef _WIN32 -double drand48(void) -{ - return (double)rand() / (double)RAND_MAX; -} - -void srand48(long int seed) -{ - srand(seed); -} -#endif |