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_ INITIALIZE_EXPO_FUNCTION func ... func.SetConstants(__VA_ARGS__) #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; }); } //GeneticAlgorithmhelperstruct structGA_Solution { unsignedshortlrgst_expo; doublerank,x,y_val; GA_Solution():lrgst_expo(0),rank(0),x(0),y_val(0){} GA_Solution(unsignedshortLrgst_expo,doubleRank,doublex_val,doubley=0):lrgst_expo(Lrgst_expo),rank(Rank),x(x_val),y_val(y){} virtual~GA_Solution()=default; voidfitness(conststd::vector<int64_t>&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; classFunction { private: constunsignedshortlrgst_expo; std::vector<int64_t>constants; boolbInitialized; voidCanPerform()const{if(!bInitialized)throwstd::logic_error("Functionobjectnotinitializedfully!Pleasecall.SetConstants()toinitialize");} public: //SpeicialtyfunctiontogettherealrootsofaQuadraticFunctionwithoutrelyingonaGeneticAlgorithmtoapproximate friendstd::vector<double>QuadraticSolve(constFunction&f); public: Function(constunsignedshort&Lrgst_expo):lrgst_expo(Lrgst_expo),bInitialized(false) { if(lrgst_expo<0) throwstd::logic_error("Functiontemplateargumentmustnotbelessthan0"); constants.reserve(Lrgst_expo); } virtual~Function(); Function(constFunction&other)=default; Function(Function&&other)noexcept=default; Function&operator=(constFunction&other)=default; Function&operator=(Function&&other)noexcept=default; voidSetConstants(conststd::vector<int64_t>&constnts); voidSetConstants(std::vector<int64_t>&&constnts); friendstd::ostream&operator<<(std::ostream&os,constFunctionfunc); friendFunctionoperator+(constFunction&f1,constFunction&f2); friendFunctionoperator-(constFunction&f1,constFunction&f2); friendFunctionoperator*(constFunction&f,constint64_t&c); Function&operator*=(constint64_t&c); [[nodiscard("MATH::EXP::Function::differential()returnsthedifferential,thecallingobjectisnotchanged")]] Functiondifferential()const; [[nodiscard]]std::vector<double>get_real_roots(constGA_Options&options=GA_Options())const; [[nodiscard]]doublesolve_y(constdouble&x_val)const; [[nodiscard]]std::vector<double>solve_x(constdouble&y_val,constGA_Options&options=GA_Options())const; [[nodiscard]]autoGetWhatIsTheLargestExponent()const{returnlrgst_expo;} }; std::vector<double>QuadraticSolve(constFunction&f) { try { if(f.lrgst_expo!=2)throwstd::logic_error("Functionfisnotaquadraticfunction"); f.CanPerform(); } catch(conststd::exception&e) { throwe; } std::vector<double>res; constauto&a=f.constants[0]; constauto&b=f.constants[1]; constauto&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; } Function::~Function() { constants.clear(); } voidFunction::SetConstants(conststd::vector<int64_t>&constnts) { 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; bInitialized=true; } voidFunction::SetConstants(std::vector<int64_t>&&constnts) { 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); bInitialized=true; } std::ostream&operator<<(std::ostream&os,constFunctionfunc) { try { func.CanPerform(); } catch(conststd::exception&e) { throwe; } if(func.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(func.lrgst_expo!=1) os<<"^"<<func.lrgst_expo; for(autoi=func.lrgst_expo-1;i>0;i--) { auton=func.constants[func.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; } auton=func.constants[func.lrgst_expo]; if(n==0)returnos; autos=n>0?"+":"-"; os<<s; os<<ABS(n); returnos; } Functionoperator+(constFunction&f1,constFunction&f2) { try { f1.CanPerform(); f2.CanPerform(); } catch(conststd::exception&e) { throwe; } autoe1=f1.lrgst_expo; autoe2=f2.lrgst_expo; autor=e1>e2?e1:e2; std::vector<int64_t>res; if(e1>e2) { for(auto&val:f1.constants) res.push_back(val); autoi=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++; } } Functionf(r); f.SetConstants(res); returnf; } Functionoperator-(constFunction&f1,constFunction&f2) { try { f1.CanPerform(); f2.CanPerform(); } catch(conststd::exception&e) { throwe; } autoe1=f1.lrgst_expo; autoe2=f2.lrgst_expo; autor=e1>e2?e1:e2; std::vector<int64_t>res; if(e1>e2) { for(auto&val:f1.constants) res.push_back(val); autoi=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++; } } Functionf(r); f.SetConstants(res); returnf; } Functionoperator*(constFunction&f,constint64_t&c) { try { f.CanPerform(); } catch(conststd::exception&e) { throwe; } if(c==1)returnf; if(c==0)throwstd::logic_error("Cannotmultiplyafunctionby0"); std::vector<int64_t>res; for(auto&val:f.constants) res.push_back(c*val); Functionf_res(f.lrgst_expo); f_res.SetConstants(res); returnf_res; } Function&Function::operator*=(constint64_t&c) { try { this->CanPerform(); } catch(conststd::exception&e) { throwe; } if(c==1)return*this; if(c==0)throwstd::logic_error("Cannotmultiplyafunctionby0"); for(auto&val:this->constants) val*=c; return*this; } FunctionFunction::differential()const { try { this->CanPerform(); } catch(conststd::exception&e) { throwe; } if(lrgst_expo==0) throwstd::logic_error("Cannotdifferentiateanumber(Function<0>)"); std::vector<int64_t>result; for(inti=0;i<lrgst_expo;i++) { result.push_back(constants[i]*(lrgst_expo-i)); } Functionf{(unsignedshort)(lrgst_expo-1)}; f.SetConstants(result); returnf; } std::vector<double>Function::get_real_roots(constGA_Options&options)const { try { this->CanPerform(); } catch(conststd::exception&e) { throwe; } //Createinitialrandomsolutions std::random_devicedevice; std::uniform_real_distribution<double>unif(options.min_range,options.max_range); std::vector<GA_Solution>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(),[this,&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>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; } doubleFunction::solve_y(constdouble&x_val)const { try { this->CanPerform(); } catch(conststd::exception&e) { throwe; } doubleans{0}; for(inti=lrgst_expo;i>=0;i--) { ans+=constants[i]*POW(x_val,(lrgst_expo-i)); } returnans; } inlinestd::vector<double>Function::solve_x(constdouble&y_val,constGA_Options&options)const { try { this->CanPerform(); } catch(conststd::exception&e) { throwe; } //Createinitialrandomsolutions std::random_devicedevice; std::uniform_real_distribution<double>unif(options.min_range,options.max_range); std::vector<GA_Solution>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(),[this,&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>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; } } } #defineINITIALIZE_EXPO_FUNCTION(func,...)\ func.SetConstants(__VA_ARGS__) #endif//!JONATHAN_RAMPERSAD_EXPONENTIAL_H_