1 /* 2 fuzzylite (R), a fuzzy logic control library in C++. 3 Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved. 4 Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com> 5 6 This file is part of fuzzylite. 7 8 fuzzylite is free software: you can redistribute it and/or modify it under 9 the terms of the FuzzyLite License included with the software. 10 11 You should have received a copy of the FuzzyLite License along with 12 fuzzylite. If not, see <http://www.fuzzylite.com/license/>. 13 14 fuzzylite is a registered trademark of FuzzyLite Limited. 15 */ 16 17 #include "test/catch.hpp" 18 #include "fl/Headers.h" 19 20 namespace fl { 21 22 /** 23 * Tests: term/Function 24 * 25 * @author Juan Rada-Vilela, Ph.D. 26 * 27 */ 28 29 TEST_CASE("function parses basic arithmetic", "[term][function]") { 30 Function f; 31 std::string text = "3+4*2/(1-5)^2^3"; 32 CHECK(f.toPostfix(text) == "3 4 2 * 1 5 - 2 3 ^ ^ / +"); 33 CHECK(f.parse(text)->toInfix() == "3.000 ^ 2.000 ^ 5.000 - 1.000 / 2.000 * 4.000 + 3.000"); 34 CHECK(f.parse(text)->toPrefix() == "+ / ^ ^ 3.000 2.000 - 5.000 1.000 * 2.000 4.000 3.000"); 35 } 36 37 TEST_CASE("function parses basic trigonometry", "[term][function]") { 38 Function f; 39 std::string text = "sin(y*x)^2/x"; 40 41 CHECK_THROWS(f.load(text)); 42 43 f.variables["y"] = 1.0; 44 f.load(text); 45 46 CHECK(f.toPostfix(text) == "y x * sin 2 ^ x /"); 47 CHECK(f.parse(text)->toInfix() == "x / 2.000 ^ x * y sin"); 48 CHECK(f.parse(text)->toPrefix() == "/ x ^ 2.000 sin * x y"); 49 } 50 51 TEST_CASE("function parses propositions", "[term][function]") { 52 Function f; 53 54 std::string text = "(Temperature is High and Oxygen is Low) or " 55 "(Temperature is Low and (Oxygen is Low or Oxygen is High))"; 56 57 CHECK(f.toPostfix(text) == "Temperature is High Oxygen is Low " 58 "and Temperature is Low Oxygen is Low Oxygen is High or and or"); 59 } 60 61 TEST_CASE("function cannot deal with negative numbers", "[term][function]") { 62 Function f; 63 std::string text = "-5 *4/sin(-pi/2)"; 64 65 SECTION("function throws exception") { 66 CHECK_THROWS(f.parse(text)->evaluate()); 67 } 68 69 f.variables["pi"] = 3.14; 70 CHECK_THROWS(f.parse(text)->evaluate(&f.variables)); 71 72 text = "~5 *4/sin(~pi/2)"; 73 CHECK(f.parse(text)->evaluate(&f.variables) == Approx(20)); 74 75 f.load(text); 76 77 f.variables["pi"] = 3.14; 78 79 CHECK(f.toPostfix(text) == "5 ~ 4 * pi ~ 2 / sin /"); 80 CHECK(f.parse(text)->toInfix() == "2.000 / pi ~ sin / 4.000 * 5.000 ~"); 81 CHECK(f.parse(text)->toPrefix() == "/ sin / 2.000 ~ pi * 4.000 ~ 5.000"); 82 } 83 84 TEST_CASE("Function is clonable", "[term][function]") { 85 Function* f = new Function; 86 std::string text = "2+2"; 87 f->load(text); 88 CHECK(Op::isEq(f->membership(fl::nan), 4)); 89 Function* clone = f->clone(); 90 delete f; 91 CHECK(Op::isEq(clone->membership(fl::nan), 4)); 92 delete clone; 93 } 94 95 TEST_CASE("Function is constructor copyable", "[term][function]") { 96 Function* f = new Function; 97 std::string text = "2+2"; 98 f->load(text); 99 CHECK(Op::isEq(f->membership(fl::nan), 4)); 100 Function* clone = new Function(*f); 101 delete f; 102 CHECK(Op::isEq(clone->membership(fl::nan), 4)); 103 delete clone; 104 } 105 106 TEST_CASE("Function computes tree size correctly", "[term][function]"){ 107 Function f("f", "x*x+(x-x)/x+log(x)"); 108 f.load(); 109 CHECK(f.root()->treeSize() == 6); 110 CHECK(f.root()->treeSize(Function::Element::Function) == 1); 111 CHECK(f.root()->treeSize(Function::Element::Operator) == 5); 112 FL_LOG(f.complexity().toString()); 113 } 114 115 } 116