diff --git a/snippets/CMakeLists.txt b/snippets/CMakeLists.txt index 10e9f69..be599e4 100644 --- a/snippets/CMakeLists.txt +++ b/snippets/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13) project(snippets) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) add_executable(pM pietMondrian.cpp) @@ -29,9 +29,9 @@ else() message(FATAL_ERROR "GTest pas trouvé") endif() -add_executable(coincheTest gTestCoinche.cpp Coinche.cpp Coinche.h) if(GTest_FOUND) + add_executable(coincheTest gTestCoinche.cpp Coinche.cpp Coinche.h) target_link_libraries(coincheTest ${GTEST_BOTH_LIBRARIES}) target_link_options(coincheTest PRIVATE -pthread) endif() @@ -46,13 +46,24 @@ target_link_libraries(parseXML pugixml) target_include_directories(parseXML PRIVATE ${PugiXML_INCLUDE_DIR}) target_link_directories(parseXML PRIVATE ${PugiXML_INCLUDE_DIR}) -add_executable(xmlTest gTestXMLParser.cpp Circle.h xmlParser.h xmlParser.cpp) - -target_include_directories(xmlTest PRIVATE ${PugiXML_INCLUDE_DIR}) -target_link_directories(xmlTest PRIVATE ${PugiXML_INCLUDE_DIR}) -target_link_libraries(xmlTest pugixml) if(GTest_FOUND) + add_executable(xmlTest gTestXMLParser.cpp Circle.h xmlParser.h xmlParser.cpp) + + target_include_directories(xmlTest PRIVATE ${PugiXML_INCLUDE_DIR}) + target_link_directories(xmlTest PRIVATE ${PugiXML_INCLUDE_DIR}) + target_link_libraries(xmlTest pugixml) + target_link_libraries(xmlTest ${GTEST_BOTH_LIBRARIES}) target_link_options(xmlTest PRIVATE -pthread) +endif() + +add_library(polynomial SHARED Polynomial.cpp Polynomial.tpp) +#target_link_libraries(polynomial -static) + +if(GTest_FOUND) + add_executable(polynomialTest gTestPolynomial.cpp) + target_link_libraries(polynomialTest ${GTEST_BOTH_LIBRARIES}) + target_link_options(polynomialTest PRIVATE -pthread) + target_link_libraries(polynomialTest polynomial) endif() \ No newline at end of file diff --git a/snippets/Polynomial.cpp b/snippets/Polynomial.cpp new file mode 100644 index 0000000..9541fc4 --- /dev/null +++ b/snippets/Polynomial.cpp @@ -0,0 +1,5 @@ +// +// Created by trotfunky on 09/05/19. +// + +#include "Polynomial.tpp" diff --git a/snippets/Polynomial.tpp b/snippets/Polynomial.tpp new file mode 100644 index 0000000..96f06df --- /dev/null +++ b/snippets/Polynomial.tpp @@ -0,0 +1,318 @@ +// +// Created by trotfunky on 09/05/19. +// + +#ifndef SNIPPETS_POLYNOMIAL_TPP +#define SNIPPETS_POLYNOMIAL_TPP + +#include +#include +#include +#include + +template class Polynomial; + +/** + * Class allowing creation, manipulation and calculation of polynomials + * Factors are stored from the lowest power to the highest + * The polynomial has at least one factor, which defaults to zero + * @tparam T Has to be an arithmetic type (std::is_arithmetic::value is true) + */ +template +class Polynomial { +public: + Polynomial(); + explicit Polynomial(const std::vector&); + explicit Polynomial(const std::map&); + + template + explicit Polynomial(const Polynomial&); + + int getDegree() const; + Polynomial getNthDerivative(int n) const; + + template + bool equals(const Polynomial&) const; + + template + auto add(const Polynomial& operand) const -> Polynomial(0) + operand[0])>; + + template + friend std::ostream& operator<<(std::ostream&, const Polynomial&); + + template + T1 operator()(const T1&) const; + + T operator[](int) const; + +private: + std::vector factors; + double factorial(unsigned int n) const; + + template + friend class Polynomial; +}; + +//////////////////// +/// /// +/// Definitions /// +/// /// +//////////////////// + +template +Polynomial::Polynomial() +{ + static_assert(std::is_arithmetic::value,"Polynomial must be of an arithmetic type!"); + factors = {0}; +} + +template +Polynomial::Polynomial(const std::vector& polynomialFactors) : Polynomial() +{ + if(polynomialFactors.size()>0) + { + factors = polynomialFactors; + } +} + +template +Polynomial::Polynomial(const std::map& polynomialFactors) : Polynomial() +{ + int degree = polynomialFactors.rbegin()->first; + if(degree >= 0) + { + factors.pop_back(); + } + factors.reserve(degree); + + for(int i = 0;i<=degree;i++) + { + auto nextFactor = polynomialFactors.find(i); + if(nextFactor != polynomialFactors.end()) + { + factors.push_back(nextFactor->second); + } + else + { + factors.push_back(0); + } + } +} + +template +template +Polynomial::Polynomial(const Polynomial& copied) +{ + static_assert(std::is_arithmetic::value,"Polynomial must be of an arithmetic type!"); + + for(const T1& factor : copied.factors) + { + factors.push_back(static_cast(factor)); + } +} + +/** + * Returns the degree of the polynomial. + * @tparam T Type of the polynomial factors + * @return Degree of the polynomial, -1 if it is the null-polynomial + */ +template +int Polynomial::getDegree() const +{ + for(int i = factors.size()-1;i>=0;i--) + { + if(factors[i] != 0) + { + return(i); + } + } + return(-1); +} + +/** + * Computes the nth derivative of the polynomial + * @tparam T Polyniaml factor type + * @param n Order of the derivative + * @return Derived polynomial, null-polynomial if the order is greater than the degree + */ +template +Polynomial Polynomial::getNthDerivative(int n) const +{ + if(n<=0) + { + return(Polynomial(*this)); + } + + if(n>getDegree()) + { + return(Polynomial()); + } + + std::vector newFactors; + + for(int i = n;i(newFactors)); +} + +template +double Polynomial::factorial(unsigned int n) const +{ + double value = 1; + for(unsigned int i = 2;i<=n;i++) + { + value *= i; + } + + return(value); +} + +template +template +bool Polynomial::equals(const Polynomial& operand) const +{ + if(getDegree() != operand.getDegree()) + { + return(false); + } + if(getDegree() == -1) + { + return(true); + } + const std::vector& p2Factors = operand.factors; + + for(int i = factors.size();i>=0;i--) + { + if(factors[i] != p2Factors[i]) + { + return(false); + } + } + + return(true); +} + +template +template +auto Polynomial::add(const Polynomial& operand) const -> Polynomial(0) + operand[0])> +{ + bool isLargest = true; + + int largestSize = factors.size(); + int smallestSize = operand.factors.size(); + + if(getDegree() < operand.getDegree()) + { + isLargest = false; + + smallestSize = factors.size(); + largestSize = operand.factors.size(); + } + + std::vector(0)+operand[0])> resultPolynomial = {}; + resultPolynomial.reserve(largestSize); + + for(int i = 0;i(0)+operand[0])>(resultPolynomial); +} + +//////////////////// +/// /// +/// Operators /// +/// /// +//////////////////// + +template +bool operator==(const Polynomial& p1, const Polynomial& p2) +{ + return(p1.equals(p2)); +} + + +/** + * Computes the sum of the two polynomials by adding factor by factor at first and pushing back + * the leftover factors from the largest polynomial if their are different in degree. + * @tparam T Type of the first polynomial + * @tparam R Type of the second polynomial + * @param p1 First polynomial + * @param p2 Second polynomial + * @return Sum of the two polynomials, null polynomial if both of them are null. The type is deduced from the addition + * of the first factors of the two polynomials. + */ +template +auto operator+(const Polynomial& p1, const Polynomial& p2) -> Polynomial +{ + return(p1.add(p2)); +} + +template +std::ostream& operator<<(std::ostream& ostream, const Polynomial& polynomial) +{ + if(polynomial.getDegree() < 0) + { + ostream << "0 "; + return ostream; + } + + const std::vector& factors = polynomial.factors; + + if(factors[0] > 0) + { + ostream << factors[0] << " "; + } + else if(factors[0] < 0) + { + ostream << std::showpos << factors[0] << " "; + } + + for(int i = 1;i +template +T1 Polynomial::operator()(const T1& input) const +{ + static_assert(std::is_arithmetic::value,"Cannot evaluate polynomial at a non arithmetic value !"); + + if(getDegree() == -1) + { + return(0); + } + + T1 returnValue = 0; + for(int i = 0;i +T Polynomial::operator[](const int index) const +{ + return(factors.at(index)); +} + + +#endif //SNIPPETS_POLYNOMIAL_TPP diff --git a/snippets/gTestPolynomial.cpp b/snippets/gTestPolynomial.cpp new file mode 100644 index 0000000..dcaf1ee --- /dev/null +++ b/snippets/gTestPolynomial.cpp @@ -0,0 +1,196 @@ +// +// Created by trotfunky on 09/05/19. +// + +#include +#include "Polynomial.tpp" + +class PolynomialOperationTest : public ::testing::Test +{ +protected: + void SetUp() override + { + pInt = Polynomial({1,2,3}); + pFloat = Polynomial({-1.0,0,2.0}); + pLarge = Polynomial({{10,1},{0,5}}); + } + + Polynomial pInt; + Polynomial pFloat; + Polynomial pLarge; +}; + +TEST(PolynomialTest,polynomialCreation) +{ + Polynomial pTestInt = Polynomial({1,2,3}); + EXPECT_EQ(pTestInt[0],1); + EXPECT_EQ(pTestInt[1],2); + EXPECT_EQ(pTestInt[2],3); + EXPECT_EQ(2,pTestInt.getDegree()); + + std::cout << "Int polynomial : " << pTestInt << std::endl; + + Polynomial pTestFloat = Polynomial({0,0,1,0}); + EXPECT_EQ(pTestFloat[0],0); + EXPECT_EQ(pTestFloat[1],0); + EXPECT_EQ(pTestFloat[2],1); + EXPECT_EQ(pTestFloat[3],0); + EXPECT_EQ(2,pTestFloat.getDegree()); + + std::cout << "Float polynomial : " << pTestFloat << std::endl; + + Polynomial pTestCopy = Polynomial(pTestInt); + EXPECT_EQ(pTestCopy[0],1); + EXPECT_EQ(pTestCopy[1],2); + EXPECT_EQ(pTestCopy[2],3); + + std::cout << pTestCopy << " is a copy of " << pTestInt << std::endl; + + Polynomial pTestMapInit = Polynomial({{0,1},{2,3},{10,10}}); + EXPECT_EQ(pTestMapInit[0],1); + EXPECT_EQ(pTestMapInit[2],3); + EXPECT_EQ(pTestMapInit[10],10); + + std::cout << "Polynomial created via a map : " << pTestMapInit << std::endl; + + std::cout << std::endl; +} + +TEST_F(PolynomialOperationTest,polynomialSum) +{ + Polynomial summedIntP = pInt + pInt; + EXPECT_EQ(summedIntP[0],2); + EXPECT_EQ(summedIntP[1],4); + EXPECT_EQ(summedIntP[2],6); + + std::cout << "Summed int polynomial : " << summedIntP << std::endl; + + Polynomial summedFloatP = pFloat + pFloat; + EXPECT_EQ(summedFloatP[0],-2.0f); + EXPECT_EQ(summedFloatP[1],0); + EXPECT_EQ(summedFloatP[2],4.0f); + + std::cout << "Summed float polynomial : " << summedFloatP << std::endl; + + auto summedAuto = pInt + pFloat; + EXPECT_EQ(summedAuto[0],0); + EXPECT_EQ(summedAuto[1],2); + EXPECT_EQ(summedAuto[2],5); + + summedAuto = pFloat + pInt; + EXPECT_EQ(summedAuto[0],0); + EXPECT_EQ(summedAuto[1],2); + EXPECT_EQ(summedAuto[2],5); + + std::cout << "Summed auto polynomial : " << summedAuto << std::endl; + + Polynomial summedLarge = pInt + pLarge; + EXPECT_EQ(summedLarge[0],6); + EXPECT_EQ(summedLarge[1],2); + EXPECT_EQ(summedLarge[2],3); + for(int i = 3;i<10;i++) + EXPECT_EQ(summedLarge[i],0); + EXPECT_EQ(summedLarge[10],1); + + std::cout << "Summed small and large polynomials : " << summedLarge << std::endl; + + std::cout << std::endl; +} + +TEST_F(PolynomialOperationTest,polynomialComparison) +{ + EXPECT_TRUE(Polynomial() == Polynomial()); + EXPECT_TRUE(Polynomial() == Polynomial()); + + Polynomial pCompInt = Polynomial({1,2,3}); + EXPECT_TRUE(pCompInt == pInt); + EXPECT_TRUE(pInt == pCompInt); + + Polynomial pCompFloat = Polynomial({-1.0,0,2.0}); + EXPECT_TRUE(pCompFloat == pFloat); + EXPECT_TRUE(pFloat == pCompFloat); + + EXPECT_TRUE(Polynomial(pFloat) == pFloat); + EXPECT_TRUE(Polynomial(pInt) == pInt); + + EXPECT_FALSE(pInt == pFloat); + EXPECT_FALSE(pInt == Polynomial()); + EXPECT_FALSE(pInt == Polynomial()); + + std::cout << std::endl; +} + +TEST_F(PolynomialOperationTest,polynomialDerivation) +{ + EXPECT_TRUE(pInt.getNthDerivative(0) == pInt); + EXPECT_TRUE(pFloat.getNthDerivative(0) == pFloat); + + std::cout << "Testing with Polynomial ..." << std::endl; + + Polynomial expectedIntDerivative = Polynomial(std::vector({2,6})); + EXPECT_TRUE(expectedIntDerivative == pInt.getNthDerivative(1)); + + std::cout << "First order derivative : " << pInt.getNthDerivative(1) << std::endl; + + expectedIntDerivative = Polynomial({6}); + EXPECT_TRUE(expectedIntDerivative == pInt.getNthDerivative(2)); + + std::cout << "Second order derivative : " << pInt.getNthDerivative(2) << std::endl; + + expectedIntDerivative = Polynomial(); + EXPECT_TRUE(expectedIntDerivative == pInt.getNthDerivative(3)); + EXPECT_TRUE(expectedIntDerivative == pInt.getNthDerivative(10)); + + std::cout << "Third order derivative : " << pInt.getNthDerivative(3) << std::endl; + std::cout << "Tenth order derivative : " << pInt.getNthDerivative(10) << std::endl; + + + std::cout << std::endl; + std::cout << "Testing with Polynomial ..." << std::endl; + + Polynomial expectedFloatDerivative = Polynomial(std::vector({0,4})); + EXPECT_TRUE(expectedFloatDerivative == pFloat.getNthDerivative(1)); + + std::cout << "First order derivative : " << pFloat.getNthDerivative(1) << std::endl; + + expectedFloatDerivative = Polynomial({4}); + EXPECT_TRUE(expectedFloatDerivative == pFloat.getNthDerivative(2)); + + std::cout << "Second order derivative : " << pFloat.getNthDerivative(2) << std::endl; + + expectedFloatDerivative = Polynomial(); + EXPECT_TRUE(expectedFloatDerivative == pFloat.getNthDerivative(3)); + EXPECT_TRUE(expectedFloatDerivative == pFloat.getNthDerivative(10)); + + std::cout << "Third order derivative : " << pFloat.getNthDerivative(3) << std::endl; + std::cout << "Tenth order derivative : " << pFloat.getNthDerivative(10) << std::endl; + + std::cout << std::endl; +} + +TEST_F(PolynomialOperationTest,polynomialAssertion) +{ + EXPECT_EQ(pInt(0),1); + EXPECT_EQ(pInt(0.0f),1); + EXPECT_EQ(pInt(1),6); + EXPECT_EQ(pInt(1.0),6); + EXPECT_EQ(pInt(-1),2); + + EXPECT_EQ(pFloat(0),-1); + EXPECT_EQ(pFloat(0.0),-1); + EXPECT_EQ(pFloat(1),1); + EXPECT_EQ(pFloat(-1),1); + + EXPECT_EQ(pLarge(0),5); + EXPECT_EQ(pLarge(1),6); + EXPECT_EQ(pLarge(2),1029); + + EXPECT_EQ(Polynomial()(100),0); + EXPECT_EQ(Polynomial()(0),0); +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc,argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file