Commit cf18fe6b authored by Andrew J. Burns (Cont's avatar Andrew J. Burns (Cont

Revert "function reading capabilities"

This reverts commit f386e633.
parent 8858e32d
#include <iostream>
#include <stack>
#include <map>
#include <string>
#include <stdlib.h>
#include <math.h>
#include <XdmfArray.hpp>
#include <XdmfArrayType.hpp>
#include "boost/assign.hpp"
double parse(std::string expression, std::map<std::string, double> variables);
double calculation(double val1, double val2, char operation);
double function(std::vector<double> valueVector, std::string functionName);
double sum(std::vector<double> values);
double ave(std::vector<double> values);
shared_ptr<XdmfArray> parse(std::string expression, std::map<std::string, shared_ptr<XdmfArray> > variables);
shared_ptr<XdmfArray> calculation(shared_ptr<XdmfArray> val1, shared_ptr<XdmfArray> val2, char operation);
shared_ptr<XdmfArray> invChunk(shared_ptr<XdmfArray> val1, shared_ptr<XdmfArray> val2);
shared_ptr<XdmfArray> function(std::vector<shared_ptr<XdmfArray> > valueVector, std::string functionName);
shared_ptr<XdmfArray> sum(std::vector<shared_ptr<XdmfArray> > values);
shared_ptr<XdmfArray> ave(std::vector<shared_ptr<XdmfArray> > values);
shared_ptr<XdmfArray> maximum(std::vector<shared_ptr<XdmfArray> > values);
std::string validDigitChars = "1234567890.";
std::string validVariableChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_:.";
//std::map<std::string, double (*)(std::vector<double>)> functions = boost::assign::map_list_of ("SUM", sum) ("AVE", ave);
std::map<std::string, double (*)(std::vector<double>)> functions = boost::assign::map_list_of ("SUM", (double (*)(std::vector<double>))sum);
//note, it doesn't handle overloaded functions well. Will generate errors unless typecast
//std::map<std::string, double (*)(std::vector<double>)> functions = boost::assign::map_list_of ("SUM", sum) ("AVE", ave);
std::map<std::string, shared_ptr<XdmfArray> (*)(std::vector<shared_ptr<XdmfArray> >)> arrayFunctions = boost::assign::map_list_of ("SUM", (shared_ptr<XdmfArray> (*)(std::vector<shared_ptr<XdmfArray> >))sum) ("MAX", (shared_ptr<XdmfArray> (*)(std::vector<shared_ptr<XdmfArray> >))maximum);
int main(int, char **)
{
XdmfArray::addFunction("MAX", maximum);
XdmfArray::addCalculation('@', invChunk, 2);
functions["AVE"] = ave;
//sometimes typecasts are required, sometimes they cause errors
//I think it needs to be cast if it isn't the first variation of the function listed
arrayFunctions["AVE"] = (shared_ptr<XdmfArray> (*)(std::vector<shared_ptr<XdmfArray> >))ave;
std::string problemToSolve = "2*twentyfive+2*3+2^(3+8)/3+8/(4+1)+SUM(4, twentyfive*4, 6) + AVE(100, 0, 0, 0)";
std::map<std::string, double> variableTable;
variableTable["twentyfive"] = 25;
variableTable["one"] = 1;
variableTable["two"] = 2;
variableTable["three"] = 3;
variableTable["four"] = 4;
variableTable["eight"] = 8;
double answer = parse(problemToSolve, variableTable);
printf("%f\n", answer);
//std::string arrayExpression = "A|B#C|D";
std::string arrayExpression = "MAX(2,(AVE(A@B)#AVE(C|D)))";
shared_ptr<XdmfArray> testArray1 = XdmfArray::New();
for (int i = 0; i < 10; i++)
{
testArray1->pushBack(1);
}
shared_ptr<XdmfArray> testArray2 = XdmfArray::New();
for (int i = 0; i < 10; i++)
{
testArray2->pushBack(2);
}
shared_ptr<XdmfArray> testArray3 = XdmfArray::New();
for (int i = 0; i < 10; i++)
{
testArray3->pushBack(3);
}
shared_ptr<XdmfArray> testArray4 = XdmfArray::New();
for (int i = 0; i < 10; i++)
{
testArray4->pushBack(4);
}
shared_ptr<XdmfArray> testArray5 = XdmfArray::New();
for (int i = 0; i < 13; i++)
{
testArray5->pushBack(5);
}
std::map<std::string, shared_ptr<XdmfArray> > arrayVariable;
arrayVariable["A"] = testArray1;
arrayVariable["B"] = testArray2;
arrayVariable["C"] = testArray3;
arrayVariable["D"] = testArray4;
arrayVariable["E"] = testArray5;
printf("before parsing\n");
shared_ptr<XdmfArray> answerArray;
answerArray = parse(arrayExpression, arrayVariable);
printf("after parsing\n");
printf("answer array = %s\n", answerArray->getValuesString());
printf("array size = %d\n", answerArray->getSize());
printf("interlace\n");
answerArray = XdmfArray::evaluateCalculation(testArray1, testArray5, '#');
printf("answer array = %s\n", answerArray->getValuesString());
printf("chunk\n");
answerArray = XdmfArray::evaluateCalculation(testArray1, testArray5, '|');
printf("answer array = %s\n", answerArray->getValuesString());
printf("inverse chunk\n");
answerArray = XdmfArray::evaluateCalculation(testArray1, testArray5, '@');
printf("answer array = %s\n", answerArray->getValuesString());
printf("after parsing\n");
printf("answer array = %s\n", answerArray->getValuesString());
printf("array size = %d\n", answerArray->getSize());
answerArray = XdmfArray::evaluateExpression(arrayExpression, arrayVariable);
printf("after parsing\n");
printf("answer array = %s\n", answerArray->getValuesString());
printf("array size = %d\n", answerArray->getSize());
return 0;
}
double parse(std::string expression, std::map<std::string, double> variables)
{
std::stack<double> valueStack;
std::stack<char> operationStack;
std::string validOperationChars = "+-*/()^"; //will be global at some point, all supported operations
int operationPriority [validOperationChars.size()];
//list the priorities for the operations, based on the order of operations
//the index of the corresponding operation in validOperationChars is the same as the index of its priority in this array
operationPriority[0] = 1;//+
operationPriority[1] = 1;//-
operationPriority[2] = 2;//*
operationPriority[3] = 2;///
operationPriority[4] = 0;//(
operationPriority[5] = 0;//)
operationPriority[6] = 3;//^
//the higher the value, the earlier the operation is evaluated in the order of operations
//with the exception of parenthesis which are evaluated as soon as the closing parenthesis is found
//string is parsed left to right
//elements of the same priority are evaluated right to left
for (int i = 0; i < expression.size(); i++)
{
if (validDigitChars.find(expression[i]) != std::string::npos)//found to be a digit
{
//progress until a non-digit is found
int valueStart = i;
while (validDigitChars.find(expression[i + 1]) != std::string::npos)
{
i++;
}
//push back to the value stack
valueStack.push(atof(expression.substr(valueStart, i + 1 - valueStart).c_str()));//use this to convert to double
}
else if (validVariableChars.find(expression[i]) != std::string::npos)//found to be a variable
{
int valueStart = i;
//progress until a nonvariable value is found
while (validVariableChars.find(expression[i + 1]) != std::string::npos)
{
i++;
}
//convert to equivalent
if (variables.find(expression.substr(valueStart, i + 1 - valueStart)) == variables.end())
{
if (functions.find(expression.substr(valueStart, i + 1 - valueStart)) == functions.end())
{
printf("Error: Invalid Variable or Function: %s\n", expression.substr(valueStart, i + 1 - valueStart));
return 0;
}
else
{
std::string currentFunction = expression.substr(valueStart, i + 1 - valueStart);
//check if next character is an open parenthesis
if (expression[i+1] != '(')
{
printf("Error: No values supplied to function %s\n", expression.substr(valueStart, i + 1 - valueStart));
return 0;
}
//if it is grab the string between paranthesis
i = i + 2;
valueStart = i;
int numOpenParenthesis = 0;
while ((expression[i] != ')' || numOpenParenthesis) && i < expression.size())
{
if (expression[i] == '(')
{
numOpenParenthesis++;
}
else if (expression[i] == ')')
{
numOpenParenthesis--;
}
i++;
}
std::string functionParameters = expression.substr(valueStart, i - valueStart);
std::vector<double> parameterVector;
//split that string at commas
size_t parameterSplit = 0;
while (parameterSplit != std::string::npos)
{
parameterSplit = 0;
parameterSplit = functionParameters.find_first_of(",", parameterSplit);
//feed the substrings to the parse function
if (parameterSplit == std::string::npos)
{
parameterVector.push_back(parse(functionParameters, variables));
}
else
{
parameterVector.push_back(parse(functionParameters.substr(0, parameterSplit), variables));
functionParameters = functionParameters.substr(parameterSplit+1);
}
}
valueStack.push(function(parameterVector, currentFunction));
}
}
else
{
//push equivalent to value stack
valueStack.push(variables.find(expression.substr(valueStart, i + 1 - valueStart))->second);
}
}
else if (validOperationChars.find(expression[i]) != std::string::npos)//found to be an operation
{
//pop operations off the stack until one of a lower or equal importance is found
if (operationStack.size() > 0)
{
if (expression[i] == ')')
{
//to close a parenthesis pop off all operations until another parentheis is found
while (operationStack.size() > 0 && operationStack.top() != '(')
{
if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
printf("Error: Not Enough Values\n");
return 0;
}
else
{
double val2 = valueStack.top();
valueStack.pop();
double val1 = valueStack.top();
valueStack.pop();
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
operationStack.pop();
}
else if (expression[i] == '(')
{
//just add it if it's a start parenthesis
//nothing happens here in that case
//addition happens after the if statement
}
else
{
size_t operationLocation = validOperationChars.find(expression[i]);
size_t topOperationLocation = validOperationChars.find(operationStack.top());
//see order of operations to determine importance
while (operationStack.size() > 0 && operationPriority[operationLocation] < operationPriority[topOperationLocation])
{
if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
printf("Error: Not Enough Values\n");
return 0;
}
else
{
double val2 = valueStack.top();
valueStack.pop();
double val1 = valueStack.top();
valueStack.pop();
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
if (operationStack.size() == 0)
{
break;
}
topOperationLocation = validOperationChars.find(operationStack.top());
}
}
}
}
if (expression[i] != ')')
{
//add the operation to the operation stack
operationStack.push(expression[i]);
}
}
//if not a value or operation the character is ignored
}
//empty what's left in the stacks before finishing
while (valueStack.size() > 1)
{
if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
printf("Error: Not Enough Values\n");
return 0;
}
else
{
if(operationStack.top() == '(')
{
printf("Warning: Unpaired Parenthesis\n");
operationStack.pop();
}
else
{
double val2 = valueStack.top();
valueStack.pop();
double val1 = valueStack.top();
valueStack.pop();
if (operationStack.size() == 0)
{
//error, not enough operations
printf("Error: Not Enough Operators\n");
return 0;
}
else
{
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
}
}
//throw error if there's extra operations
if (operationStack.size() > 0)
{
printf("Warning: Left Over Operators\n");
}
return valueStack.top();
}
double calculation(double val1, double val2, char operation)
{
//perform the appropriate operation as designated by the string supplied
if (operation == '+')//addition
{
return val1 + val2;
}
else if (operation == '-')//subtraction
{
return val1 - val2;
}
else if (operation == '*')//multiplication
{
return val1 * val2;
}
else if (operation == '/')//division
{
return val1 / val2;
}
else if (operation == '^')//exponent
{
return pow(val1, val2);
}
//insert new operations into this huge if statement
return 0.0;//return 0 as a default
}
//this is how you use references to functions
double function(std::vector<double> valueVector, std::string functionName)
{
return (*functions[functionName])(valueVector);
}
double sum(std::vector<double> values)
{
double total = 0.0;
for (int i = 0; i < values.size(); i++)
{
total += values[i];
}
return total;
}
double ave(std::vector<double> values)
{
double total = sum(values);
return total/values.size();
}
shared_ptr<XdmfArray> parse(std::string expression, std::map<std::string, shared_ptr<XdmfArray> > variables)
{
std::stack<shared_ptr<XdmfArray> > valueStack;
std::stack<char> operationStack;
std::string validOperationChars = "|#()@"; //will be global at some point, all supported operations
int operationPriority [validOperationChars.size()];
//list the priorities for the operations, based on the order of operations
//the index of the corresponding operation in validOperationChars is the same as the index of its priority in this array
operationPriority[0] = 2;//|
operationPriority[1] = 1;//#
operationPriority[2] = 0;//(
operationPriority[3] = 0;//)
operationPriority[4] = 2;//@
//the higher the value, the earlier the operation is evaluated in the order of operations
//with the exception of parenthesis which are evaluated as soon as the closing parenthesis is found
//string is parsed left to right
//elements of the same priority are evaluated right to left
for (int i = 0; i < expression.size(); i++)
{
if (validDigitChars.find(expression[i]) != std::string::npos)//found to be a digit
{
//progress until a non-digit is found
int valueStart = i;
while (validDigitChars.find(expression[i + 1]) != std::string::npos)
{
i++;
}
//push back to the value stack
//create a new array to hold the value
shared_ptr<XdmfArray> valueArray = XdmfArray::New();
valueArray->insert(0, atof(expression.substr(valueStart, i + 1 - valueStart).c_str()));
valueStack.push(valueArray);
}
else if (validVariableChars.find(expression[i]) != std::string::npos)//found to be a variable
{
int valueStart = i;
//progress until a nonvariable value is found
while (validVariableChars.find(expression[i + 1]) != std::string::npos)
{
i++;
}
//convert to equivalent
if (variables.find(expression.substr(valueStart, i + 1 - valueStart)) == variables.end())
{
if (arrayFunctions.find(expression.substr(valueStart, i + 1 - valueStart)) == arrayFunctions.end())
{
printf("Error: Invalid Variable or Function\n");
return XdmfArray::New();
}
else
{
std::string currentFunction = expression.substr(valueStart, i + 1 - valueStart);
//check if next character is an open parenthesis
if (expression[i+1] != '(')
{
printf("Error: No Values Supplied to Function %s\n", expression.substr(valueStart, i + 1 - valueStart));
return XdmfArray::New();
}
//if it is grab the string between paranthesis
i = i + 2;
valueStart = i;
int numOpenParenthesis = 0;
while ((expression[i] != ')' || numOpenParenthesis) && i < expression.size())
{
if (expression[i] == '(')
{
numOpenParenthesis++;
}
else if (expression[i] == ')')
{
numOpenParenthesis--;
}
i++;
}
std::string functionParameters = expression.substr(valueStart, i - valueStart);
std::vector<shared_ptr<XdmfArray> > parameterVector;
//split that string at commas
size_t parameterSplit = 0;
while (parameterSplit != std::string::npos)
{
parameterSplit = 0;
parameterSplit = functionParameters.find_first_of(",", parameterSplit);
//feed the substrings to the parse function
if (parameterSplit == std::string::npos)
{
parameterVector.push_back(parse(functionParameters, variables));
}
else
{
parameterVector.push_back(parse(functionParameters.substr(0, parameterSplit), variables));
functionParameters = functionParameters.substr(parameterSplit+1);
}
}
valueStack.push(function(parameterVector, currentFunction));
}
}
else
{
//push equivalent to value stack
valueStack.push(variables.find(expression.substr(valueStart, i + 1 - valueStart))->second);
}
}
else if (validOperationChars.find(expression[i]) != std::string::npos)//found to be an operation
{
//pop operations off the stack until one of a lower or equal importance is found
if (operationStack.size() > 0)
{
if (expression[i] == ')')
{
//to close a parenthesis pop off all operations until another parentheis is found
while (operationStack.size() > 0 && operationStack.top() != '(')
{
if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
return XdmfArray::New();
}
else
{
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
operationStack.pop();
}
else if (expression[i] == '(')
{
//just add it if it's a start parenthesis
//nothing happens here in that case
//addition happens after the if statement
}
else
{
size_t operationLocation = validOperationChars.find(expression[i]);
size_t topOperationLocation = validOperationChars.find(operationStack.top());
//see order of operations to determine importance
while (operationStack.size() > 0 && operationPriority[operationLocation] < operationPriority[topOperationLocation])
{
if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
printf("Error: Not Enough Values\n");
return XdmfArray::New();
}
else
{
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
if (operationStack.size() == 0)
{
break;
}
topOperationLocation = validOperationChars.find(operationStack.top());
}
}
}
}
if (expression[i] != ')')
{
//add the operation to the operation stack
operationStack.push(expression[i]);
}
}
//if not a value or operation the character is ignored
}
//empty what's left in the stacks before finishing
while (valueStack.size() > 1 && operationStack.size() > 0)
{
if(operationStack.top() == '(')
{
printf("Warning: Unpaired Parenthesis\n");
operationStack.pop();
}
else if (valueStack.size() < 2)//must be at least two values for this loop to work properly
{
//error, not enough values
printf("Error: Not Enough Values\n");
return XdmfArray::New();
}
else
{
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
if (operationStack.size() == 0)
{
//error, not enough operations
printf("Error: Not Enough Operators\n");
return XdmfArray::New();
}
else
{
valueStack.push(calculation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
}
//throw error if there's extra operations
if (operationStack.size() > 0)
{
printf("Warning: Left Over Operators\n");
}
if (valueStack.size() > 1)
{
printf("Warning: Left Over Values\n");
}
return valueStack.top();
}
shared_ptr<XdmfArray> calculation(shared_ptr<XdmfArray> val1, shared_ptr<XdmfArray> val2, char operation)
{
//perform the appropriate operation as designated by the string supplied
if (operation == '|')//join chunk (add the new array to the end of the first one)
{
//joins into new array and returns it
shared_ptr<XdmfArray> returnArray = XdmfArray::New();
returnArray->insert(0, val1, 0, val1->getSize(), 1, 1);
returnArray->insert(val1->getSize(), val2, 0, val2->getSize(), 1, 1);
return returnArray;
}
else if (operation == '@')//inverse chunk
{
//joins into new array and returns it
shared_ptr<XdmfArray> returnArray = XdmfArray::New();
returnArray->insert(0, val2, 0, val2->getSize(), 1, 1);
returnArray->insert(val2->getSize(), val1, 0, val1->getSize(), 1, 1);
return returnArray;
}
else if (operation == '#')//join interlace (evenly space the second array within the first one)
{
//builds a new array
shared_ptr<XdmfArray> returnArray = XdmfArray::New();
//resize to the combined size of both arrays
//might not be required?
//what type to class it as?
shared_ptr<const XdmfArrayType> arrayType1 = val1->getArrayType();
shared_ptr<const XdmfArrayType> arrayType2 = val2->getArrayType();
if (arrayType1 == XdmfArrayType::Int8())
{
//if floats reclass as floats of the appropriate size
if (arrayType2 == XdmfArrayType::String())
{
//string is the only compatible type here
std::string sampleValue = "";
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Float32())
{
float sampleValue = 0.0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Float64())
{
double sampleValue = 0.0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
//if uints reclass as ints of the appropriate size
else if (arrayType2 == XdmfArrayType::Int64() || arrayType2 == XdmfArrayType::UInt32())
{
long sampleValue = 0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Int32() || arrayType2 == XdmfArrayType::UInt16())
{
int sampleValue = 0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Int16() || arrayType2 == XdmfArrayType::UInt8())
{
short sampleValue = 0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else
{
char sampleValue = 0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
}
else if (arrayType1 == XdmfArrayType::Int16())
{
//if floats reclass as floats of the appropriate size
if (arrayType2 == XdmfArrayType::String())
{
//string is the only compatible type here
std::string sampleValue = "";
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Float32())
{
float sampleValue = 0.0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
else if (arrayType2 == XdmfArrayType::Float64())
{
double sampleValue = 0.0;
returnArray->resize(val1->getSize()+val2->getSize(), sampleValue);
}
//if uints reclass as ints of the appropriate size
else if (arrayType2 == XdmfArrayType::Int64() || arrayType2 == XdmfArrayType::UInt32())
{
long sampleValue = 0;