Exponential.h ostream vector float.h random algorithm execution exception Exponential/Source.cpp JRAMPERSAD::EXPONENTIAL::GA_Options JRAMPERSAD::EXPONENTIAL::Function JRAMPERSAD JRAMPERSAD::EXPONENTIAL JRAMPERSAD::EXPONENTIAL::detail JONATHAN_RAMPERSAD_EXPONENTIAL_H_ #pragmaonce #ifndefJONATHAN_RAMPERSAD_EXPONENTIAL_H_ #defineJONATHAN_RAMPERSAD_EXPONENTIAL_H_ #include<ostream> #include<vector> #include<float.h> #include<random> #include<algorithm> #include<execution> #include<exception> namespaceJRAMPERSAD { namespaceEXPONENTIAL { structGA_Options { doublemin_range=-100; doublemax_range=100; unsignedintnum_of_generations=10; unsignedintsample_size=1000; unsignedintdata_size=100000; doublemutation_percentage=0.01; }; namespacedetail { template<typenameT> [[nodiscard("MATH::ABS(T)returnsavalueoftypeT")]]TABS(constT&n)noexcept { returnn<0?n*-1:n; } template<typenameT> [[nodiscard("MATH::NEGATE(T)returnsavalueoftypeT")]]TNEGATE(constT&n)noexcept { returnn*-1; } template<typenameT> [[nodiscard("MATH::POW(T,int)returnsavalueoftypeT")]]TPOW(constT&n,constint&exp)noexcept { if(exp==0) return1; Tres=n; for(inti=1;i<exp;i++) { res*=n; } returnres; } template<typenameT> [[nodiscard("MATH::SUM(std::vector<T>)returnsavalueoftypeT")]]TSUM(conststd::vector<T>&vec)noexcept { Tres{}; for(auto&val:vec) res+=val; returnres; } template<typenameT> [[nodiscard]]TMEDIAN(std::vector<T>vec)noexcept { std::sort( vec.begin(), vec.end(), [](constauto&lhs,constauto&rhs){ returnlhs<rhs; }); returnvec[vec.size()/2]; } template<typenameT> [[nodiscard]]doubleMEAN(conststd::vector<T>&vec)noexcept { returnSUM(vec)/vec.size(); } template<typenameT> [[noreturn]]voidSortASC(std::vector<T>&vec) { std::sort( std::execution::par, vec.begin(),vec.end(), [](constauto&lhs,constauto&rhs){ returnlhs<rhs; }); } template<typenameT> [[noreturn]]voidSortDESC(std::vector<T>&vec) { std::sort( std::execution::par, vec.begin(),vec.end(), [](constauto&lhs,constauto&rhs){ returnlhs>rhs; }); } template<intlrgst_expo>//GeneticAlgorithmhelperstruct structGA_Solution { doublerank,x,y_val; boolranked; GA_Solution():rank(0),x(0),y_val(0),ranked(false){} GA_Solution(doubleRank,doublex_val,doubley=0):rank(Rank),x(x_val),y_val(y),ranked(false){} virtual~GA_Solution()=default; voidfitness(conststd::vector<int>&constants) { doubleans=0; for(inti=lrgst_expo;i>=0;i--) ans+=constants[i]*POW(x,(lrgst_expo-i)); ans-=y_val; rank=(ans==0)?DBL_MAX:ABS(1/ans); } }; } usingnamespacedetail; template<intlrgst_expo> classFunction { private: std::vector<int>constants; public: //SpeicialtyfunctiontogettherealrootsofaQuadraticFunctionwithoutrelyingonaGeneticAlgorithmtoapproximate friendstd::vector<double>QuadraticSolve(constFunction<2>&f); public: Function(conststd::vector<int>&constnts); Function(std::vector<int>&&constnts); Function(constFunction&other)=default; Function(Function&&other)noexcept=default; virtual~Function(); Function&operator=(constFunction&other)=default; Function&operator=(Function&&other)noexcept=default; //Operatorfunctiontodisplayfunctionobjectinahumanreadableformat friendstd::ostream&operator<<(std::ostream&os,constFunction<lrgst_expo>func) { if(lrgst_expo==0) { os<<func.constants[0]; returnos; } if(func.constants[0]==1) os<<"x"; elseif(func.constants[0]==-1) os<<"-x"; else os<<func.constants[0]<<"x"; if(lrgst_expo!=1) os<<"^"<<lrgst_expo; for(inti=lrgst_expo-1;i>0;i--) { intn=func.constants[lrgst_expo-i]; if(n==0)continue; autos=n>0?"+":"-"; if(n!=1) os<<s<<ABS(n)<<"x"; else os<<s<<"x"; if(i!=1) os<<"^"<<i; } intn=func.constants[lrgst_expo]; if(n==0)returnos; autos=n>0?"+":"-"; os<<s; os<<ABS(n); returnos; } template<inte1,inte2,intr> friendFunction<r>operator+(constFunction<e1>&f1,constFunction<e2>&f2);//Operatortoaddtwofunctions template<inte1,inte2,intr> friendFunction<r>operator-(constFunction<e1>&f1,constFunction<e2>&f2);//Operatortosubtracttwofunctions //Operatorstomultiplyafunctionbyaconstant(Scalingit) friendFunction<lrgst_expo>operator*(constFunction<lrgst_expo>&f,constint&c) { if(c==1)returnf; if(c==0)throwstd::logic_error("Cannotmultiplyafunctionby0"); std::vector<int>res; for(auto&val:f.constants) res.push_back(c*val); returnFunction<lrgst_expo>(res); } Function<lrgst_expo>&operator*=(constint&c) { if(c==1)return*this; if(c==0)throwstd::logic_error("Cannotmultiplyafunctionby0"); for(auto&val:this->constants) val*=c; return*this; } [[nodiscard("MATH::EXP::Function::differential()returnsthedifferential,thecallingobjectisnotchanged")]] Function<lrgst_expo-1>differential()const; [[nodiscard]]std::vector<double>get_real_roots(constGA_Options&options=GA_Options())const; [[nodiscard]]doublesolve_y(constdouble&x_val)constnoexcept; [[nodiscard]]std::vector<double>solve_x(constdouble&y_val,constGA_Options&options=GA_Options())const; }; std::vector<double>QuadraticSolve(constFunction<2>&f) { std::vector<double>res; constint&a=f.constants[0]; constint&b=f.constants[1]; constint&c=f.constants[2]; constdoublesqr_val=static_cast<double>(POW(b,2)-(4*a*c)); if(sqr_val<0) { returnres; } res.push_back(((NEGATE(b)+sqrt(sqr_val))/2*a)); res.push_back(((NEGATE(b)-sqrt(sqr_val))/2*a)); returnres; } template<inte1,inte2,intr=(e1>e2?e1:e2)> Function<r>operator+(constFunction<e1>&f1,constFunction<e2>&f2) { std::vector<int>res; if(e1>e2) { for(auto&val:f1.constants) res.push_back(val); inti=e1-e2; for(auto&val:f2.constants) { res[i]+=val; i++; } } else { for(auto&val:f2.constants) res.push_back(val); inti=e2-e1; for(auto&val:f1.constants) { res[i]+=val; i++; } } returnFunction<r>{res}; } template<inte1,inte2,intr=(e1>e2?e1:e2)> Function<r>operator-(constFunction<e1>&f1,constFunction<e2>&f2) { std::vector<int>res; if(e1>e2) { for(auto&val:f1.constants) res.push_back(val); inti=e1-e2; for(auto&val:f2.constants) { res[i]-=val; i++; } } else { for(auto&val:f2.constants) res.push_back(val); inti=e2-e1; for(intj=0;j<i;j++) res[j]*=-1; for(auto&val:f1.constants) { res[i]=val-res[i]; i++; } } returnFunction<r>{res}; } template<intlrgst_expo> Function<lrgst_expo>::Function(conststd::vector<int>&constnts) { if(lrgst_expo<0) throwstd::logic_error("Functiontemplateargumentmustnotbelessthan0"); if(constnts.size()!=lrgst_expo+1) throwstd::logic_error("Function<n>mustbecreatedwith(n+1)integersinvectorobject"); if(constnts[0]==0) throwstd::logic_error("Firstvalueshouldnotbe0"); constants=constnts; } template<intlrgst_expo> Function<lrgst_expo>::Function(std::vector<int>&&constnts) { if(lrgst_expo<0) throwstd::logic_error("Functiontemplateargumentmustnotbelessthan0"); if(constnts.size()!=lrgst_expo+1) throwstd::logic_error("Function<n>mustbecreatedwith(n+1)integersinvectorobject"); if(constnts[0]==0) throwstd::logic_error("Firstvalueshouldnotbe0"); constants=std::move(constnts); } template<intlrgst_expo> Function<lrgst_expo>::~Function() { constants.clear(); } template<intlrgst_expo> Function<lrgst_expo-1>Function<lrgst_expo>::differential()const { if(lrgst_expo==0) throwstd::logic_error("Cannotdifferentiateanumber(Function<0>)"); std::vector<int>result; for(inti=0;i<lrgst_expo;i++) { result.push_back(constants[i]*(lrgst_expo-i)); } returnFunction<lrgst_expo-1>{result}; } template<intlrgst_expo> std::vector<double>Function<lrgst_expo>::get_real_roots(constGA_Options&options)const { //Createinitialrandomsolutions std::random_devicedevice; std::uniform_real_distribution<double>unif(options.min_range,options.max_range); std::vector<GA_Solution<lrgst_expo>>solutions; solutions.resize(options.data_size); for(unsignedinti=0;i<options.sample_size;i++) solutions[i]=(GA_Solution<lrgst_expo>{0,unif(device)}); floattimer{0}; for(unsignedintcount=0;count<options.num_of_generations;count++) { std::generate(std::execution::par,solutions.begin()+options.sample_size,solutions.end(),[&unif,&device](){ returnGA_Solution<lrgst_expo>{0,unif(device)}; }); //Runourfitnessfunction for(auto&s:solutions){s.fitness(constants);} //Sortoursolutionsbyrank std::sort(std::execution::par,solutions.begin(),solutions.end(), [](constauto&lhs,constauto&rhs){ returnlhs.rank>rhs.rank; }); //Taketopsolutions std::vector<GA_Solution<lrgst_expo>>sample; std::copy( solutions.begin(), solutions.begin()+options.sample_size, std::back_inserter(sample) ); solutions.clear(); if(count+1==options.num_of_generations) { std::copy( sample.begin(), sample.end(), std::back_inserter(solutions) ); sample.clear(); break; } //Mutatethetopsolutionsby% std::uniform_real_distribution<double>m((1-options.mutation_percentage),(1+options.mutation_percentage)); std::for_each(sample.begin(),sample.end(),[&m,&device](auto&s){ s.x*=m(device); }); //Crossovernotneededasit'sonlyonevalue std::copy( sample.begin(), sample.end(), std::back_inserter(solutions) ); sample.clear(); solutions.resize(options.data_size); } std::sort(solutions.begin(),solutions.end(), [](constauto&lhs,constauto&rhs){ returnlhs.x<rhs.x; }); std::vector<double>ans; for(auto&s:solutions) { ans.push_back(s.x); } returnans; } template<intlrgst_expo> doubleFunction<lrgst_expo>::solve_y(constdouble&x_val)constnoexcept { std::vector<bool>exceptions; for(inti:constants) exceptions.push_back(i!=0); doubleans{0}; for(inti=lrgst_expo;i>=0;i--) { if(exceptions[i]) ans+=constants[i]*POW(x_val,(lrgst_expo-i)); } returnans; } template<intlrgst_expo> inlinestd::vector<double>Function<lrgst_expo>::solve_x(constdouble&y_val,constGA_Options&options)const { //Createinitialrandomsolutions std::random_devicedevice; std::uniform_real_distribution<double>unif(options.min_range,options.max_range); std::vector<GA_Solution<lrgst_expo>>solutions; solutions.resize(options.data_size); for(unsignedinti=0;i<options.sample_size;i++) solutions[i]=(GA_Solution<lrgst_expo>{0,unif(device),y_val}); for(unsignedintcount=0;count<options.num_of_generations;count++) { std::generate(std::execution::par,solutions.begin()+options.sample_size,solutions.end(),[&unif,&device,&y_val](){ returnGA_Solution<lrgst_expo>{0,unif(device),y_val}; }); //Runourfitnessfunction for(auto&s:solutions){s.fitness(constants);} //Sortoursolutionsbyrank std::sort(std::execution::par,solutions.begin(),solutions.end(), [](constauto&lhs,constauto&rhs){ returnlhs.rank>rhs.rank; }); //Taketopsolutions std::vector<GA_Solution<lrgst_expo>>sample; std::copy( solutions.begin(), solutions.begin()+options.sample_size, std::back_inserter(sample) ); solutions.clear(); if(count+1==options.num_of_generations) { std::copy( sample.begin(), sample.end(), std::back_inserter(solutions) ); sample.clear(); break; } //Mutatethetopsolutionsby% std::uniform_real_distribution<double>m((1-options.mutation_percentage),(1+options.mutation_percentage)); std::for_each(sample.begin(),sample.end(),[&m,&device](auto&s){ s.x*=m(device); }); //Crossovernotneededasit'sonlyonevalue std::copy( sample.begin(), sample.end(), std::back_inserter(solutions) ); sample.clear(); solutions.resize(options.data_size); } std::sort(solutions.begin(),solutions.end(), [](constauto&lhs,constauto&rhs){ returnlhs.x<rhs.x; }); std::vector<double>ans; for(auto&s:solutions) { ans.push_back(s.x); } returnans; } } } #endif//!JONATHAN_RAMPERSAD_EXPONENTIAL_H_