...
 
Commits (5)
#[[
# CMakeLists.txt
#
# This file is part of formula_parser.
#
# A CMake configuration file
#
# ]]
project(formula_parser
LANGUAGES CXX C Fortran)
cmake_minimum_required(VERSION 3.9)
########### Download and compile googletest ###############
enable_testing()
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
include(GoogleTest)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
############################# formula_parser ##################################
set( CMAKE_CXX_STANDARD 17 )
set( CMAKE_CXX_STANDARD_REQUIRED on)
# The C++-library
add_library(formula_parser SHARED STATIC
src/formula_parser.cxx)
# C-interface
add_library(formula_parser_c SHARED STATIC
src/formula_parser_c.cc)
add_dependencies(formula_parser_c
formula_parser)
# Fortran-interface
add_library(formula_parser_f SHARED STATIC
src/formula_parser_f.f90)
add_dependencies(formula_parser_f
formula_parser formula_parser_c)
# Tests
add_executable(formula_parser_tests src/formula_parser_tests.cxx)
target_link_libraries(formula_parser_tests gtest gtest_main formula_parser)
gtest_discover_tests(formula_parser_tests)
#include <iostream>
#include "formula_parser.h"
#include <fstream>
#include <string>
#include <vector>
#include <array>
// Save 2d vector to file (append)
template <std::size_t size_x, std::size_t size_y>
void vector2d2file(std::string filename, double (&arr)[size_x][size_y]) {
std::ofstream out(filename.c_str(), std::ios::trunc);
for(unsigned i=0;i<size_x;i++) {
for(unsigned j=0;j<size_y;j++) {
out << arr[i][j] << " ";
}
out << std::endl;
}
out.close();
}
int main()
{
formula_parser parser;
parser.add_variables({"x","y"});
parser.add_constant("xL", 480);
parser.add_constant("yL", 580);
parser.add_constant("offset", 10);
parser.add_constant("yc", 400);
parser.add_constant("p", 0.8);
parser.add_constant("discont", 50);
parser.add_constant("wy2", 40.876685201774535);
parser.add_constant("yd", 539.1233147982255);
parser.add_constant("xd", 399.4459384178116);
parser.add_constant("yc2", 350);
parser.add_constant("xc", 342.8652214031487);
parser.add_constant("xc2", 384.);
parser.add_constant("kl", -0.8226955719370256);
parser.add_constant("cl", 671.943450177959);
parser.add_constant("a", 750.2018588877584);
parser.add_constant("b", 4254.606163353555);
//parser.parse("max((y-yd)/wy2, (abs(x)-xd)/(xL-xd))*step(y-yd) + step((abs(x)-(kl*y+cl))/(xL-(kl*y+cl)))*step(y-yc2)*step(yc-y)*(abs(x)-(kl*y+cl))/(xL-(kl*y+cl)) + (abs(x) - a/b*sqrt(y)*sqrt(2*b+y)-offset)/(xL-a/b*sqrt(y)*sqrt(2*b+y)-offset)*step(y-yc)*step((yL-wy2)-y) * step((abs(x) - a/b*sqrt(y)*sqrt(2*b+y)-offset)/(xL-a/b*sqrt(y)*sqrt(2*b+y)-offset))");
auto fun = parser.get_function();
const unsigned Nx=600;
const unsigned Ny=600;
double arr[Nx][Ny];
double dx = 2*480.0/Nx;
double dy = 2*580.0/Ny;
for(unsigned i=0;i<Nx;i+=1) {
for(unsigned j=0;j<Ny;j+=1){
arr[i][j]=fun({-480+dx*i,-580+dy*j});
}
}
vector2d2file("tmp", arr);
return 0;
}
#include <iostream>
#include "formula_parser.h"
int main(int argc, char **argv)
{
formula_parser parser;
parser.add_variables({"x","y"});
parser.add_constant("yc", 400);
parser.add_constant("p", 430);
parser.add_constant("a", 750.202);
parser.add_constant("b", 4254.61);
parser.add_constant("wy2", 51);
parser.add_constant("yc2", 350);
parser.add_constant("kl", -1.73975);
parser.add_constant("cl", 1028.77);
parser.add_constant("offset", 0);
parser.add_constant("xL", 480);
parser.add_constant("yL", 580);
parser.parse("step(y - yc2)*step(yc - y)*(abs(x) - (kl*y + cl))/(xL - (kl*y + cl)) + step(y - (yL - wy2))*(y - (yL - wy2))/ wy2 + (abs(x) - a/b*sqrt(y)*sqrt(2*b + y) - offset)/(xL -a/b*sqrt(y)*sqrt(2*b + y) - offset)* step(y - yc)*step((yL - wy2) - y)");
auto fun = parser.get_function();
std::cout << fun({1,2}) << std::endl;
return 0;
}
......@@ -7,8 +7,10 @@
#include "formula_parser.h"
double step(double x) {
return x>0.0 ? 1.0 : 0.0;
double step(double x){
if (x > 0) return 1.0;
if (x < 0) return 0.0;
else return 0.5;
}
formula_parser::formula_parser(){
......@@ -20,15 +22,17 @@ formula_parser::formula_parser(){
add_operator("/", 2, std::divides<double>(), associativity::left, 2);
add_operator("^", 2, static_cast<double(*)(double, double)>(&std::pow), associativity::right, 2);
// Add pre-defined functions
add_function("log", 1, &log);
add_function("ln", 1, &log);
add_function("exp", 1, &exp);
add_function("exp2", 1, &exp2);
add_function("log2", 1, &log2);
add_function("log10", 1, &log10);
add_function("sqrt", 1, &sqrt);
add_function("abs", 1, &fabs);
// Add pre-defined functions, static_cast helps to resolve overloads
typedef double ftype(const double);
add_function("ln", 1, static_cast<ftype*>(&std::log));
add_function("log", 1, static_cast<ftype*>(&std::log));
add_function("log10", 1, static_cast<ftype*>(&std::log10));
add_function("log2", 1, static_cast<ftype*>(&std::log10));
add_function("exp2", 1, static_cast<ftype*>(&std::exp2));
add_function("exp", 1, static_cast<ftype*>(&std::exp));
add_function("sqrt", 1, static_cast<ftype*>(&std::sqrt));
add_function("abs", 1, &std::fabs<double>);
add_function("max", 2, &std::fmax<double, double>);
add_function("step", 1, &step);
// Add pre-defined constants
......@@ -139,7 +143,6 @@ void formula_parser::parse(std::string expression){
bool next_is_possibly_unary_operator = true;
while(expression.size() != 0){
std::cout << expression << std::endl;
std::tie(rtok_type, rtok, rint, rassoc) = get_next_token(expression, next_is_possibly_unary_operator);
switch(rtok_type){
......@@ -192,8 +195,6 @@ void formula_parser::parse(std::string expression){
break;
case(token_type::parenths_right):
std::cout << opers.size() << std::endl;
std::cout << (std::get<0>(opers.top()) == token_type::parenths_left) << std::endl;
while(!opers.empty() and (std::get<0>(opers.top()) != token_type::parenths_left) ){
postfix.push_back(std::make_pair(std::get<0>(opers.top()), std::get<1>(opers.top())));
opers.pop();
......
......@@ -14,7 +14,6 @@
#include <stack>
#include <utility>
#include <tuple>
#include <cassert>
#include <locale>
#include <algorithm>
#include <stdexcept>
......@@ -22,6 +21,8 @@
#include <type_traits>
#include <boost/variant.hpp>
#include <boost/math/constants/constants.hpp>
#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test
using namespace boost::math::double_constants;
......@@ -40,6 +41,7 @@ public:
};
private:
friend class formula_parser_tests;
enum class token_type {
binary_operator,
unary_operator,
......
......@@ -3,87 +3,104 @@
#include "gtest/gtest.h"
#include <type_traits>
TEST(token_parser, plus) {
auto res = is_a_token("+");
class formula_parser_tests : public ::testing::Test {
protected:
void test_plus() {
auto res = parser.is_a_token("+");
EXPECT_TRUE(std::get<0>(res));
EXPECT_TRUE(std::get<0>(res));
EXPECT_EQ(token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(token_type::unary_operator == std::get<1>(res));
EXPECT_EQ(formula_parser::token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::unary_operator == std::get<1>(res));
auto oper = boost::get<binary_oper>(std::get<2>(res));
auto oper = boost::get<formula_parser::function_2>(std::get<2>(res));
EXPECT_EQ(3, oper(1,2));
EXPECT_EQ(3, oper(1,2));
}
}
void test_minus(){
auto parser = formula_parser();
auto res = parser.is_a_token("-");
TEST(token_parser, binary_minus) {
auto res = is_a_token("-", false);
EXPECT_TRUE(std::get<0>(res));
EXPECT_TRUE(std::get<0>(res));
EXPECT_EQ(formula_parser::token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::unary_operator == std::get<1>(res));
EXPECT_EQ(token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(token_type::unary_operator == std::get<1>(res));
auto oper = boost::get<formula_parser::function_2>(std::get<2>(res));
auto oper = boost::get<binary_oper>(std::get<2>(res));
EXPECT_EQ(-1, oper(1,2));
}
EXPECT_EQ(-1, oper(1,2));
void test_unary_minus(){
auto parser = formula_parser();
auto res = parser.is_a_token("-", true);
}
EXPECT_TRUE(std::get<0>(res));
TEST(token_parser, unary_minus) {
auto res = is_a_token("-",true);
EXPECT_EQ(formula_parser::token_type::unary_operator, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::binary_operator == std::get<1>(res));
EXPECT_TRUE(std::get<0>(res));
auto oper = boost::get<formula_parser::function_1>(std::get<2>(res));
EXPECT_EQ(token_type::unary_operator, std::get<1>(res));
EXPECT_FALSE(token_type::binary_operator == std::get<1>(res));
EXPECT_EQ(-2, oper(2));
}
auto oper = boost::get<unary_oper>(std::get<2>(res));
void test_divide(){
auto parser = formula_parser();
auto res = parser.is_a_token("/");
EXPECT_EQ(-1, oper(1));
EXPECT_TRUE(std::get<0>(res));
}
EXPECT_EQ(formula_parser::token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::unary_operator == std::get<1>(res));
TEST(token_parser, divide) {
auto res = is_a_token("/");
auto oper = boost::get<formula_parser::function_2>(std::get<2>(res));
EXPECT_TRUE(std::get<0>(res));
EXPECT_EQ(0.5, oper(1,2));
}
EXPECT_EQ(token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(token_type::unary_operator == std::get<1>(res));
void test_multiply(){
auto parser = formula_parser();
auto res = parser.is_a_token("*");
auto oper = boost::get<binary_oper>(std::get<2>(res));
EXPECT_TRUE(std::get<0>(res));
EXPECT_EQ(1.5, oper(3,2));
EXPECT_EQ(formula_parser::token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::unary_operator == std::get<1>(res));
}
auto oper = boost::get<formula_parser::function_2>(std::get<2>(res));
TEST(token_parser, multiply) {
auto res = is_a_token("*");
EXPECT_EQ(4, oper(2,2));
}
EXPECT_TRUE(std::get<0>(res));
void test_log(){
auto parser = formula_parser();
auto res = parser.is_a_token("log");
EXPECT_EQ(token_type::binary_operator, std::get<1>(res));
EXPECT_FALSE(token_type::unary_operator == std::get<1>(res));
EXPECT_TRUE(std::get<0>(res));
auto oper = boost::get<binary_oper>(std::get<2>(res));
EXPECT_EQ(formula_parser::token_type::function_1, std::get<1>(res));
EXPECT_FALSE(formula_parser::token_type::binary_operator == std::get<1>(res));
EXPECT_EQ(6, oper(3,2));
}
auto oper = boost::get<formula_parser::function_1>(std::get<2>(res));
TEST(token_parser, log) {
auto res = is_a_token("log");
EXPECT_EQ(0, oper(1));
}
private:
formula_parser parser;
};
EXPECT_TRUE(std::get<0>(res));
TEST_F(formula_parser_tests, plus){ test_plus(); }
TEST_F(formula_parser_tests, minus){ test_minus(); }
TEST_F(formula_parser_tests, unary_minus){ test_unary_minus(); }
TEST_F(formula_parser_tests, divide){ test_divide(); }
TEST_F(formula_parser_tests, multiply){ test_multiply(); }
TEST_F(formula_parser_tests, log){ test_log(); }
EXPECT_EQ(token_type::function1, std::get<1>(res));
EXPECT_FALSE(token_type::unary_operator == std::get<1>(res));
auto oper = boost::get<unary_oper>(std::get<2>(res));
/*
EXPECT_EQ(0, oper(1));
}
TEST(token_parser, left_parenthesis){
auto res = is_a_token("(");
......@@ -423,13 +440,12 @@ TEST(shunting_yard_parse, parenths_1){
TEST(shunting_yard_evaluate, simple1){
std::string expression = "1+2-3";
class
auto inpout = shunting_yard_parse(expression);
auto value = shunting_yard_evaluate(inpout);
EXPECT_EQ(0, value);
}
TEST(shunting_yard_evaluate, simple2){
std::string expression = "1+2+3";
......@@ -566,7 +582,7 @@ TEST(shunting_yard_evaluate, expr5){
EXPECT_TRUE(fabs(0.37374783761546421 - value)<1e-6);
}
*/
int main(int argc, char** argv){
testing::InitGoogleTest(&argc, argv);
......