Get vector from exprTk as output

673 Views Asked by At

I can't seem to get a vector output from exprTk. I figure it should be relatively simple but in the manual I can only find how to input a vector and not how to output one.

What I currently have is the following:

typedef double T; // numeric type (float, double, mpfr etc...)
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T>     expression_t;
typedef exprtk::parser<T>             parser_t;

std::string expression_string = "var z[2] := { x, y };";

T x = T(5.3);
T y = T(2.3);
std::vector<T> z;

symbol_table_t symbol_table;
symbol_table.add_variable("x", x);
symbol_table.add_variable("y", y);
symbol_table.add_vector("z", z);

expression_t expression;
expression.register_symbol_table(symbol_table);

//Check if expression is valid
parser_t parser;
if (!parser.compile(expression_string, expression))
{
    printf("Compilation error...\n");
    return;
}

T result = expression.value();
std::cout << result << std::endl;     \\returns: 5.3 as expected the first element of vector z.
std::cout << z[0] << std::endl;       \\Crashes the program 

What I want as output is just the vector z. How do I do this, or what am I doing wrong?

2

There are 2 best solutions below

1
On BEST ANSWER

I've found a method that does work, but hopefully there is a simpler 'one-line' method

std::string expression_string = "var w[2] := { x, y }; z := w";

This creates an expression local vector w ([SECTION 13 - VARIABLE, VECTOR & STRING DEFINITION]), and then assigns the value to z

As @NathanOliver mentioned, std::vector<T> z(2); is also needed


"var z[2] := { x, y };" doesn't work as it is an illegal redefinition of the z variable, due to the use of the var statement.

Note that "z := {x, y}" will also not work as this does not appear to be a valid assignment expression for a vector


Output (with debug enabled):

prev[var] --> curr[var]
prev[var] --> curr[w]
prev[2] --> curr[]]
prev[x] --> curr[,]
prev[y] --> curr[}]
parse_define_vector_statement() - INFO - Added new local vector: w[2]
activate_side_effect() - caller: parse_define_vector_statement()
parse_corpus(00) Subexpr: var w[2] := { x, y };
parse_corpus(00) - Side effect present: true
-------------------------------------------------
prev[z] --> curr[:=]
prev[:=] --> curr[w]
prev[w] --> curr[]
activate_side_effect() - caller: lodge_assignment()
parse_corpus(01) Subexpr: z := w
parse_corpus(01) - Side effect present: true
-------------------------------------------------
5.3
5.3
4
On

As per Section 20 - Expression Return Values of the readme, One can immediately exit an expression returning any number of variables of any type simply by using the return statement.

The example provided in the documentation is as follows:

std::string expression_string =
   " if (x < y)                                   "
   "   return [x + 1,'return-call 1'];            "
   " else if (x > y)                              "
   "   return [y / 2, y + 1, 'return-call 2'];    "
   " else if (equal(x,y))                         "
   "   x + y;                                     "
   " return [x, y, x + y, x - y, 'return-call 3'] ";

typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double>     expression_t;
typedef exprtk::parser<double>             parser_t;

symbol_table_t symbol_table;
expression_t   expression;
parser_t       parser;

double x = 0;
double y = 0;

symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);

expression.register_symbol_table(symbol_table);

parser.compile(expression_string,expression);

T result = expression.value();

if (expression.results().count())
{
   typedef exprtk::results_context<T> results_context_t;
   typedef typename results_context_t::type_store_t type_t;
   typedef typename type_t::scalar_view scalar_t;
   typedef typename type_t::vector_view vector_t;
   typedef typename type_t::string_view string_t;

   const results_context_t& results = expression.results();

   for (std::size_t i = 0; i < results.count(); ++i)
   {
      type_t t = results[i];

      switch (t.type)
      {
         case type_t::e_scalar : ...
                                 break;

         case type_t::e_vector : ...
                                 break;

         case type_t::e_string : ...
                                 break;

         default               : continue;
      }
}

Note1: Your expression will become:

var z[2] := { x, y }; return [z];

Note2: In order to have your "one-line" method you could write a simple free function that wraps the boiler plate code after the conditional and extracts the vector of your choosing (i'th result given it's of vector type) from the results list.

template <typename T>
bool get_vector(const std::size_t index, 
                const results_context_t& results,
                std::vector<T>& v)
{
   ...
}