2#ifndef JONATHAN_RAMPERSAD_EXPONENTIAL_H_
3#define JONATHAN_RAMPERSAD_EXPONENTIAL_H_
39 [[nodiscard(
"MATH::ABS(T) returns a value of type T")]] T ABS(
const T& n)
noexcept
41 return n < 0 ? n * -1 : n;
45 [[nodiscard(
"MATH::NEGATE(T) returns a value of type T")]] T NEGATE(
const T& n)
noexcept
51 [[nodiscard(
"MATH::POW(T, int) returns a value of type T")]] T POW(
const T& n,
const int& exp)
noexcept
57 for (
int i = 1; i < exp; i++)
66 [[nodiscard(
"MATH::SUM(std::vector<T>) returns a value of type T")]] T SUM(
const std::vector<T>& vec)
noexcept
75 [[nodiscard]] T MEDIAN(std::vector<T> vec)
noexcept
80 [](
const auto& lhs,
const auto& rhs) {
84 return vec[vec.size() / 2];
88 [[nodiscard]]
double MEAN(
const std::vector<T>& vec)
noexcept
90 return SUM(vec) / vec.size();
94 [[noreturn]]
void SortASC(std::vector<T>& vec)
98 vec.begin(), vec.end(),
99 [](
const auto& lhs,
const auto& rhs) {
105 [[noreturn]]
void SortDESC(std::vector<T>& vec)
109 vec.begin(), vec.end(),
110 [](
const auto& lhs,
const auto& rhs) {
118 unsigned short lrgst_expo;
119 double rank, x, y_val;
121 GA_Solution() : lrgst_expo(0), rank(0), x(0), y_val(0) {}
122 GA_Solution(
unsigned short Lrgst_expo,
double Rank,
double x_val,
double y = 0) : lrgst_expo(Lrgst_expo), rank(Rank), x(x_val), y_val(y) {}
123 virtual ~GA_Solution() =
default;
125 void fitness(
const std::vector<int64_t>& constants)
128 for (
int i = lrgst_expo; i >= 0; i--)
129 ans += constants[i] * POW(x, (lrgst_expo - i));
132 rank = (ans == 0) ? DBL_MAX : ABS(1 / ans);
137 using namespace detail;
144 const unsigned short lrgst_expo;
145 std::vector<int64_t> constants;
149 void CanPerform()
const {
if (!bInitialized)
throw std::logic_error(
"Function object not initialized fully! Please call .SetConstants() to initialize"); }
160 Function(
const unsigned short& Lrgst_expo) : lrgst_expo(Lrgst_expo), bInitialized(false)
163 throw std::logic_error(
"Function template argument must not be less than 0");
164 constants.reserve(Lrgst_expo);
181 void SetConstants(
const std::vector<int64_t>& constnts);
200 [[nodiscard(
"MATH::EXP::Function::differential() returns the differential, the calling object is not changed")]]
215 [[nodiscard]]
double solve_y(
const double& x_val)
const;
234 std::vector<double> QuadraticSolve(
const Function& f)
238 if (f.lrgst_expo != 2)
throw std::logic_error(
"Function f is not a quadratic function");
241 catch (
const std::exception& e)
246 std::vector<double> res;
248 const auto& a = f.constants[0];
249 const auto& b = f.constants[1];
250 const auto& c = f.constants[2];
252 const double sqr_val =
static_cast<double>(POW(b, 2) - (4 * a * c));
259 res.push_back(((NEGATE(b) + sqrt(sqr_val)) / 2 * a));
260 res.push_back(((NEGATE(b) - sqrt(sqr_val)) / 2 * a));
271 if (constnts.size() != lrgst_expo + 1)
272 throw std::logic_error(
"Function<n> must be created with (n+1) integers in vector object");
274 if (constnts[0] == 0)
275 throw std::logic_error(
"First value should not be 0");
277 constants = constnts;
283 if (constnts.size() != lrgst_expo + 1)
284 throw std::logic_error(
"Function<n> must be created with (n+1) integers in vector object");
286 if (constnts[0] == 0)
287 throw std::logic_error(
"First value should not be 0");
289 constants = std::move(constnts);
294 std::ostream& operator<<(std::ostream& os,
const Function func)
300 catch (
const std::exception& e)
305 if (func.lrgst_expo == 0)
307 os << func.constants[0];
311 if (func.constants[0] == 1)
313 else if (func.constants[0] == -1)
316 os << func.constants[0] <<
"x";
318 if (func.lrgst_expo != 1)
319 os <<
"^" << func.lrgst_expo;
321 for (
auto i = func.lrgst_expo - 1; i > 0; i--)
323 auto n = func.constants[func.lrgst_expo - i];
324 if (n == 0)
continue;
326 auto s = n > 0 ?
" + " :
" - ";
329 os << s << ABS(n) <<
"x";
337 auto n = func.constants[func.lrgst_expo];
338 if (n == 0)
return os;
340 auto s = n > 0 ?
" + " :
" - ";
356 catch (
const std::exception& e)
361 auto e1 = f1.lrgst_expo;
362 auto e2 = f2.lrgst_expo;
363 auto r = e1 > e2 ? e1 : e2;
365 std::vector<int64_t> res;
368 for (
auto& val : f1.constants)
372 for (
auto& val : f2.constants)
380 for (
auto& val : f2.constants)
384 for (
auto& val : f1.constants)
404 catch (
const std::exception& e)
409 auto e1 = f1.lrgst_expo;
410 auto e2 = f2.lrgst_expo;
411 auto r = e1 > e2 ? e1 : e2;
413 std::vector<int64_t> res;
416 for (
auto& val : f1.constants)
420 for (
auto& val : f2.constants)
428 for (
auto& val : f2.constants)
433 for (
int j = 0; j < i; j++)
436 for (
auto& val : f1.constants)
438 res[i] = val - res[i];
455 catch (
const std::exception& e)
460 if (c == 1)
return f;
461 if (c == 0)
throw std::logic_error(
"Cannot multiply a function by 0");
463 std::vector<int64_t> res;
464 for (
auto& val : f.constants)
465 res.push_back(c * val);
480 catch (
const std::exception& e)
485 if (c == 1)
return *
this;
486 if (c == 0)
throw std::logic_error(
"Cannot multiply a function by 0");
488 for (
auto& val : this->constants)
500 catch (
const std::exception& e)
506 throw std::logic_error(
"Cannot differentiate a number (Function<0>)");
508 std::vector<int64_t> result;
509 for (
int i = 0; i < lrgst_expo; i++)
511 result.push_back(constants[i] * (lrgst_expo - i));
514 Function f{ (
unsigned short)(lrgst_expo - 1) };
526 catch (
const std::exception& e)
532 std::random_device device;
534 std::vector<GA_Solution> solutions;
537 for (
unsigned int i = 0; i < options.
sample_size; i++)
538 solutions[i] = (GA_Solution{lrgst_expo, 0, unif(device)});
544 std::generate(std::execution::par, solutions.begin() + options.
sample_size, solutions.end(), [
this, &unif, &device]() {
545 return GA_Solution{lrgst_expo, 0, unif(device)};
549 for (
auto& s : solutions) { s.fitness(constants); }
552 std::sort(std::execution::par, solutions.begin(), solutions.end(),
553 [](
const auto& lhs,
const auto& rhs) {
554 return lhs.rank > rhs.rank;
558 std::vector<GA_Solution> sample;
562 std::back_inserter(sample)
571 std::back_inserter(solutions)
579 std::for_each(sample.begin(), sample.end(), [&m, &device](
auto& s) {
588 std::back_inserter(solutions)
594 std::sort(solutions.begin(), solutions.end(),
595 [](
const auto& lhs,
const auto& rhs) {
596 return lhs.x < rhs.x;
599 std::vector<double> ans;
600 for (
auto& s : solutions)
607 double Function::solve_y(
const double& x_val)
const
613 catch (
const std::exception& e)
619 for (
int i = lrgst_expo; i >= 0; i--)
621 ans += constants[i] * POW(x_val, (lrgst_expo - i));
626 inline std::vector<double> Function::solve_x(
const double& y_val,
const GA_Options& options)
const
632 catch (
const std::exception& e)
638 std::random_device device;
640 std::vector<GA_Solution> solutions;
643 for (
unsigned int i = 0; i < options.
sample_size; i++)
644 solutions[i] = (GA_Solution{lrgst_expo, 0, unif(device), y_val});
648 std::generate(std::execution::par, solutions.begin() + options.
sample_size, solutions.end(), [
this, &unif, &device, &y_val]() {
649 return GA_Solution{lrgst_expo, 0, unif(device), y_val};
654 for (
auto& s : solutions) { s.fitness(constants); }
657 std::sort(std::execution::par, solutions.begin(), solutions.end(),
658 [](
const auto& lhs,
const auto& rhs) {
659 return lhs.rank > rhs.rank;
663 std::vector<GA_Solution> sample;
667 std::back_inserter(sample)
676 std::back_inserter(solutions)
684 std::for_each(sample.begin(), sample.end(), [&m, &device](
auto& s) {
693 std::back_inserter(solutions)
699 std::sort(solutions.begin(), solutions.end(),
700 [](
const auto& lhs,
const auto& rhs) {
701 return lhs.x < rhs.x;
704 std::vector<double> ans;
705 for (
auto& s : solutions)
714#define INITIALIZE_EXPO_FUNCTION(func, ...) \
715func.SetConstants(__VA_ARGS__)
class representing an Exponential Function (e.g 2x^2 + 4x - 1)
Definition Exponential.h:142
Function & operator*=(const int64_t &c)
Definition Exponential.h:474
Function(const Function &other)=default
Copy Constructor.
Function(Function &&other) noexcept=default
Move Constructor.
std::vector< double > get_real_roots(const GA_Options &options=GA_Options()) const
Uses a genetic algorithm to find the approximate roots of the function.
Definition Exponential.h:520
double solve_y(const double &x_val) const
Solves for y when x = user value.
Definition Exponential.h:607
Function & operator=(const Function &other)=default
Copy Assignment operator.
friend Function operator*(const Function &f, const int64_t &c)
Definition Exponential.h:449
friend Function operator-(const Function &f1, const Function &f2)
Definition Exponential.h:397
Function(const unsigned short &Lrgst_expo)
Constructor for Function class.
Definition Exponential.h:160
auto GetWhatIsTheLargestExponent() const
Definition Exponential.h:226
friend std::ostream & operator<<(std::ostream &os, const Function func)
Definition Exponential.h:294
friend std::vector< double > QuadraticSolve(const Function &f)
Uses the quadratic function to solve the roots of an entered quadratic equation.
Definition Exponential.h:234
void SetConstants(const std::vector< int64_t > &constnts)
Sets the constants of the function.
Definition Exponential.h:269
friend Function operator+(const Function &f1, const Function &f2)
Definition Exponential.h:349
std::vector< double > solve_x(const double &y_val, const GA_Options &options=GA_Options()) const
Uses a genetic algorithm to find the values of x where y = user value.
Definition Exponential.h:626
Function differential() const
Calculates the differential (dy/dx) of the Function.
Definition Exponential.h:494
Function & operator=(Function &&other) noexcept=default
Move Assignment operator.
virtual ~Function()
Destructor.
Definition Exponential.h:264
Structure for options to be used when running one of the two genetic algorithms in a Function object.
Definition Exponential.h:21
double min_range
Minimum value you believe the answer can be.
Definition Exponential.h:23
unsigned int num_of_generations
Number of times you'd like to run the algorithm (increasing this value causes the algorithm to take l...
Definition Exponential.h:27
unsigned int data_size
Amount of solutions you'd like the algorithm to generate (increasing this value causes the algorithm ...
Definition Exponential.h:31
double mutation_percentage
How much you'd like the algorithm to mutate solutions (Leave this as default in most cases)
Definition Exponential.h:33
double max_range
Maximum value you believe the answer can be.
Definition Exponential.h:25
unsigned int sample_size
Amount of approximate solutions you'd like to be returned.
Definition Exponential.h:29