Rewrite initial commit

This commit is contained in:
quentin 2024-02-07 09:39:57 -06:00
parent 089e9115f1
commit c8203d4308
31 changed files with 21 additions and 1084 deletions

12
.idea/dataSources.xml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="SQLite - accounts.sqlite" uuid="12a339a0-479d-435e-9bcd-76796d62848c">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/budget/accounts.sqlite</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

6
.idea/discord.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
</component>
</project>

View File

@ -3,16 +3,6 @@ project(budget)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
add_executable(${PROJECT_NAME} src/main.cpp src/main.h add_executable(${PROJECT_NAME} src/main.cpp)
src/money/account.cpp src/money/account.h
src/money/payment.cpp src/money/payment.h target_link_libraries(${PROJECT_NAME} sqlite3)
src/money/recept.cpp src/money/recept.h
src/data/data.tpp src/data/data.h
src/data/accountData.cpp src/data/accountData.h
src/money/earning.cpp src/money/earning.h
src/data/dateMoney.cpp src/data/dateMoney.h
src/optHandlers/optHandler.cpp src/optHandlers/optHandler.h
src/optHandlers/accountOptHandler.cpp src/optHandlers/accountOptHandler.h
src/optHandlers/mainOptHandler.cpp src/optHandlers/mainOptHandler.h
utilities/math.cpp utilities/math.h
utilities/polynomialFunction.cpp utilities/polynomialFunction.h src/money/transaction.cpp src/money/transaction.h)

View File

@ -1,99 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#include "accountData.h"
#include <iostream>
AccountData::AccountData(const std::string &file) : Data(file) {
account = AccountData::createObject();
}
AccountData::AccountData(const std::string &file, const std::string &name) : Data(file) {
std::string json = R"({"name":")" + name + R"(","payments":[],"earnings":[]})";
document.Parse(json.c_str());
account = AccountData::createObject();
std::cout << "Created account " << name << std::endl;
}
Account AccountData::createObject() {
if (isJsonCorrect()) {
std::string name = document["name"].GetString();
std::list<Payment> payments;
for (auto &domPayment : document["payments"].GetArray()) {
Receipt receipt(domPayment["receipt"]["file"].GetString());
double value = domPayment["value"].GetDouble();
std::time_t date = domPayment["date"].GetInt64();
std::tm tmTime{};
std::memcpy(&tmTime, std::localtime(&date), sizeof(struct tm));
payments.emplace_back(value, receipt, tmTime);
}
std::list<Earning> earnings;
for (auto &domEarning : document["earnings"].GetArray()) {
double value = domEarning["value"].GetDouble();
std::time_t date = domEarning["date"].GetInt64();
std::tm tmTime{};
std::memcpy(&tmTime, std::localtime(&date), sizeof(struct tm));
earnings.emplace_back(value, tmTime);
}
return Account(payments, earnings, name);
}
std::string strAnswer;
bool answer;
while (true) {
std::cout << "Account " + getFilePath() + " Is malformed, would you like to remove it? (Y/n): ";
std::cin >> strAnswer;
std::transform(strAnswer.begin(), strAnswer.end(), strAnswer.begin(), ::toupper);
if (strAnswer == "Y" || strAnswer == "YES") {
answer = true;
break;
}
if (strAnswer == "N" || strAnswer == "NO") {
answer = false;
break;
}
std::cout << "Sorry, answer " + strAnswer + " not understood." << std::endl;
}
return Account();
}
bool AccountData::isJsonCorrect() {
if (document.IsObject() &&
document.HasMember("name") && document["name"].IsString() &&
document.HasMember("payments") && document["payments"].IsArray() &&
document.HasMember("earnings") && document["earnings"].IsArray()) {
for (auto &domPayment : document["payments"].GetArray()) {
if (!(domPayment.IsObject() &&
domPayment.HasMember("receipt") && domPayment["receipt"].IsObject() &&
domPayment["receipt"].HasMember("file") && domPayment["receipt"]["file"].IsString() &&
domPayment.HasMember("value") && domPayment["value"].IsDouble() &&
domPayment.HasMember("date") && domPayment["date"].IsInt64())) {
return false;
}
}
for (auto &domEarning : document["earnings"].GetArray()) {
if (!(domEarning.IsObject() &&
domEarning.HasMember("value") && domEarning["value"].IsDouble() &&
domEarning.HasMember("date") && domEarning["date"].IsInt64())) {
return false;
}
}
return true;
}
return false;
}
Account *AccountData::getAccount() {
return &account;
}
AccountData::AccountData() : Data("/dev/null") {}

View File

@ -1,36 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#ifndef BUDGET_ACCOUNTDATA_H
#define BUDGET_ACCOUNTDATA_H
#include "data.h"
#include "../money/account.h"
static const char *jsonTemplate = "";
class AccountData : private Data<Account> {
public:
AccountData();
AccountData(const AccountData &) = default;
explicit AccountData(const std::string &file);
explicit AccountData(const std::string &file, const std::string &name);
Account *getAccount();
using Data<Account>::deleteObject;
private:
Account account;
Account createObject() override;
bool isJsonCorrect() override;
};
#endif //BUDGET_ACCOUNTDATA_H

View File

@ -1,43 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#ifndef BUDGET_DATA_H
#define BUDGET_DATA_H
#include <pwd.h>
#include <unistd.h>
#include <string>
#include <rapidjson/document.h>
template<class T>
class Data {
public:
rapidjson::Document document;
virtual ~Data();
Data(const Data &data);
explicit Data(std::string file);
virtual T createObject() = 0;
std::string getFilePath();
void flushToFile();
void deleteObject();
private:
const std::string fileName;
const std::string homeDirectory = getpwuid(getuid())->pw_dir;
std::string fileDirectory;
bool flush = true;
virtual bool isJsonCorrect() = 0;
};
#include "data.tpp"
#endif //BUDGET_DATA_H

View File

@ -1,85 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#include "data.h"
#include <utility>
#include <fstream>
#include <vector>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <sstream>
template<class T>
Data<T>::Data(std::string file) : fileName(std::move(file)) {
// Create file if it doesnt exist
std::ifstream chkExistIfs(getFilePath(), std::ios::in | std::ios::binary | std::ios::ate);
if (chkExistIfs) {
// File exists, were not creating one
std::ifstream::pos_type fileSize = chkExistIfs.tellg();
chkExistIfs.seekg(0, std::ios::beg);
std::vector<char> bytes(fileSize);
chkExistIfs.read(bytes.data(), fileSize);
document.Parse(std::string(bytes.data(), fileSize).c_str());
chkExistIfs.close();
} else {
// File doesnt exist we need to create one
// This is the job of the derives constructor.
chkExistIfs.close();
};
}
template<class T>
std::string Data<T>::getFilePath() {
return fileName;
}
template<class T>
void Data<T>::flushToFile() {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
std::ofstream file(getFilePath());
file << buffer.GetString();
file.close();
}
template<class T>
Data<T>::~Data() {
if (flush) {
flushToFile();
}
}
template<class T>
void Data<T>::deleteObject() {
remove(getFilePath().c_str());
flush = false;
}
template<class T>
Data<T>::Data(const Data &data) : fileName(data.fileName) {
// Create file if it doesnt exist
std::ifstream chkExistIfs(getFilePath(), std::ios::in | std::ios::binary | std::ios::ate);
if (chkExistIfs) {
// File exists, were not creating one
std::ifstream::pos_type fileSize = chkExistIfs.tellg();
chkExistIfs.seekg(0, std::ios::beg);
std::vector<char> bytes(fileSize);
chkExistIfs.read(bytes.data(), fileSize);
document.Parse(std::string(bytes.data(), fileSize).c_str());
chkExistIfs.close();
} else {
// File doesnt exist we need to create one
// This is the job of the derives constructor.
chkExistIfs.close();
};
}

View File

@ -1,38 +0,0 @@
//
// Created by quentin on 8/12/22.
//
#include "dateMoney.h"
DateMoney::DateMoney(const double *value, tm *date) : value(value), date(date) {}
bool DateMoney::operator<(const DateMoney &rhs) const {
return mktime(date) < mktime(rhs.date);
}
bool DateMoney::operator>(const DateMoney &rhs) const {
return rhs < *this;
}
bool DateMoney::operator<=(const DateMoney &rhs) const {
return !(rhs < *this);
}
bool DateMoney::operator>=(const DateMoney &rhs) const {
return !(*this < rhs);
}
std::ostream &operator<<(std::ostream &os, const DateMoney &money) {
os << "Value: " << *money.value << " Date: " << money.date->tm_mon + 1 << "/" << money.date->tm_mday << "/"
<< money.date->tm_year+1900;
return os;
}
const double *DateMoney::getValue() const {
return value;
}
tm *DateMoney::getDate() const {
return date;
}

View File

@ -1,36 +0,0 @@
//
// Created by quentin on 8/12/22.
//
#ifndef BUDGET_DATEMONEY_H
#define BUDGET_DATEMONEY_H
#include <ctime>
#include <ostream>
class DateMoney {
public:
DateMoney(const double *value, tm *date);
[[nodiscard]] const double *getValue() const;
[[nodiscard]] tm *getDate() const;
bool operator<(const DateMoney &rhs) const;
bool operator>(const DateMoney &rhs) const;
bool operator<=(const DateMoney &rhs) const;
bool operator>=(const DateMoney &rhs) const;
friend std::ostream &operator<<(std::ostream &os, const DateMoney &money);
private:
const double *value;
tm *date;
};
#endif //BUDGET_DATEMONEY_H

View File

@ -2,110 +2,7 @@
// Created by quentin on 8/3/22. // Created by quentin on 8/3/22.
// //
#include "main.h"
#include "data/accountData.h"
#include "optHandlers/accountOptHandler.h"
#include "optHandlers/mainOptHandler.h"
#include "../utilities/math.h"
#include <pwd.h>
#include <unistd.h>
#include <string>
#include <filesystem>
#include <unordered_map>
#include <iostream>
using namespace Budget;
const std::string homeDirectory = getpwuid(getuid())->pw_dir;
const std::string configD = homeDirectory + "/.config/budget/";
const std::string storageD = homeDirectory + "/.local/share/budget/";
void createRequiredFolders() {
std::filesystem::create_directory(configD);
std::filesystem::create_directories(storageD);
std::filesystem::create_directories(storageD + "accounts");
std::filesystem::create_directories(storageD + "receipts");
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::vector<char *> args(argv, argv + argc);
// Parse main options (-ah)
OptHandlers::MainOptHandler mainOptHandler(args);
mainOptHandler.parse();
if (mainOptHandler.getSetOpts()->help)
mainOptHandler.help();
createRequiredFolders();
// Read all accounts saved and store them in accounts
std::unordered_map<std::string, AccountData> accounts;
for (const auto &file : std::filesystem::directory_iterator(
homeDirectory + "/.local/share/budget/accounts")) {
AccountData account(file.path());
accounts.insert(std::pair(account.getAccount()->getName(), account));
}
// Parse account options if main options tells us to.
if (mainOptHandler.getSetOpts()->account) {
std::vector<char *> vec{argv[0]};
vec.insert(vec.end(), args.begin() + mainOptHandler.getSetOpts()->accountArgStart, args.end());
OptHandlers::AccountOptHandler accountOptHandler(vec);
accountOptHandler.parse();
// Do what we need to do for parsed options
if (accountOptHandler.getSetOpts()->help) {
accountOptHandler.help();
}
if (accountOptHandler.getSetOpts()->create) {
auto a = accounts.find(accountOptHandler.getSetOpts()->delAccount);
if (a == accounts.end()) {
accounts.emplace(std::piecewise_construct,
std::make_tuple(accountOptHandler.getSetOpts()->createAccount), std::make_tuple(
storageD + "accounts/" + accountOptHandler.getSetOpts()->createAccount + ".json",
accountOptHandler.getSetOpts()->createAccount));
} else {
std::cout << "Account " << accountOptHandler.getSetOpts()->delAccount << " already exists."
<< std::endl;
}
}
if (accountOptHandler.getSetOpts()->value) {
auto a = accounts.find(accountOptHandler.getSetOpts()->valueAccount);
if (a != accounts.end()) {
int value = a->second.getAccount()->getValue();
std::vector<DateMoney> timeline = a->second.getAccount()->getTimeline();
printf("Account value: %d\n", value);
printf("Last 10 transactions:\n");
for (int i = 0; i < timeline.size() && i < 10; i++) {
const double *amount = timeline[i].getValue();
const tm *date = timeline[i].getDate();
if (*amount <= 0) {
// Red
printf("Value: \033[31m%.2f\033[0m, ", *amount);
}
else {
// Green
printf("Value: \033[32m%.2f\033[0m, ", *amount);
}
printf("Date: %d/%d/%d\n", date->tm_mon+1, date->tm_mday, date->tm_year+1900);
}
std::cout << std::endl;
}
}
if (accountOptHandler.getSetOpts()->del) {
auto a = accounts.find(accountOptHandler.getSetOpts()->delAccount);
if (a != accounts.end()) {
accounts.erase(a);
std::cout << "Deleted account: " << accountOptHandler.getSetOpts()->delAccount << std::endl;
}
}
if (accountOptHandler.getSetOpts()->list) {
std::cout << "Accounts: " << std::endl;
for (auto &accountPair : accounts) {
std::cout << accountPair.second.getAccount()->getName() << ": " << std::endl;
std::cout << " Value: " << accountPair.second.getAccount()->getValue() << std::endl;
}
}
}
return 0; return 0;
} }

View File

@ -1,8 +0,0 @@
//
// Created by quentin on 8/12/22.
//
#ifndef BUDGET_MAIN_H
#define BUDGET_MAIN_H
#endif //BUDGET_MAIN_H

View File

@ -1,44 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#include "account.h"
#include <utility>
Account::Account(std::list<Payment> payments, std::list<Earning> earnings,
std::string name) : payments(std::move(payments)), earnings(std::move(earnings)),
name(std::move(name)) {}
Account::Account() {
name = "";
}
int Account::getValue() {
int total = 0;
for (auto &payment : payments) {
total -= payment.value;
}
for (auto &earning : earnings) {
total += earning.value;
}
return total;
}
std::vector<DateMoney> Account::getTimeline() {
std::vector<DateMoney> timeline;
for (auto &payment : payments) {
timeline.emplace_back(payment.getValue(), payment.getDate());
}
for (auto &earning : earnings) {
timeline.emplace_back(&earning.value, earning.getDate());
}
std::sort(timeline.begin(), timeline.end(), std::greater<>());
return timeline;
}
const std::string &Account::getName() const {
return name;
}

View File

@ -1,35 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#ifndef BUDGET_ACCOUNT_H
#define BUDGET_ACCOUNT_H
#include "payment.h"
#include "earning.h"
#include "../data/dateMoney.h"
#include <list>
#include <string>
#include <vector>
class Account {
public:
Account(std::list<Payment> payments, std::list<Earning> earnings, std::string name);
Account();
int getValue();
std::vector<DateMoney> getTimeline();
[[nodiscard]] const std::string &getName() const;
private:
std::list<Payment> payments;
std::list<Earning> earnings;
std::string name;
};
#endif //BUDGET_ACCOUNT_H

View File

@ -1,7 +0,0 @@
//
// Created by quentin on 8/11/22.
//
#include "earning.h"
Earning::Earning(const double value, std::tm date) : Transaction(value, date) {}

View File

@ -1,17 +0,0 @@
//
// Created by quentin on 8/11/22.
//
#ifndef BUDGET_EARNING_H
#define BUDGET_EARNING_H
#include <ctime>
#include "transaction.h"
class Earning : public Transaction {
public:
explicit Earning(double value, std::tm date);
};
#endif //BUDGET_EARNING_H

View File

@ -1,19 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#include "payment.h"
#include <utility>
Payment::Payment(const double value, Receipt receipt, std::tm date) : Transaction(value, date), receipt(std::move(receipt)) {
negativeValue = -value;
}
Receipt &Payment::getReceipt() {
return receipt;
}
const double *Payment::getValue() {
return &negativeValue;
}

View File

@ -1,27 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#ifndef BUDGET_PAYMENT_H
#define BUDGET_PAYMENT_H
#include "recept.h"
#include "transaction.h"
class Payment : public Transaction {
public:
Payment(double value, Receipt receipt, std::tm date);
Receipt &getReceipt();
const double *getValue();
private:
Receipt receipt;
double negativeValue;
};
#endif //BUDGET_PAYMENT_H

View File

@ -1,9 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#include "recept.h"
#include <utility>
Receipt::Receipt(std::string file) : file(std::move(file)) {}

View File

@ -1,21 +0,0 @@
//
// Created by quentin on 8/4/22.
//
#ifndef BUDGET_RECEPT_H
#define BUDGET_RECEPT_H
#include <string>
class Receipt {
private:
public:
explicit Receipt(std::string file);
private:
std::string file;
};
#endif //BUDGET_RECEPT_H

View File

@ -1,11 +0,0 @@
//
// Created by quentin on 9/16/22.
//
#include "transaction.h"
Transaction::Transaction(const double value, const tm &date) : value(value), date(date) {}
tm *Transaction::getDate() {
return &date;
}

View File

@ -1,23 +0,0 @@
//
// Created by quentin on 9/16/22.
//
#ifndef BUDGET_TRANSACTION_H
#define BUDGET_TRANSACTION_H
#include <ctime>
class Transaction {
public:
Transaction(double value, const tm &date);
const double value;
tm *getDate();
private:
std::tm date;
};
#endif //BUDGET_TRANSACTION_H

View File

@ -1,70 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#include <iostream>
#include "accountOptHandler.h"
using namespace Budget::OptHandlers;
void AccountOptHandler::parse() {
struct option longOpts[] = {
{"help", no_argument, nullptr, 'h'},
{"list", no_argument, nullptr, 'l'},
{"delete", required_argument, nullptr, 'd'},
{"create", required_argument, nullptr, 'c'},
{"value", required_argument, nullptr, 'v'},
};
while (true) {
int opt = getopt_long(getArgc(), getArgv(), "hld:c:v:", longOpts, nullptr);
if (opt == -1) {
break;
}
switch (opt) {
case 'h':
setOpts.help = true;
break;
case 'l':
setOpts.list = true;
break;
case 'd':
setOpts.del = true;
setOpts.delAccount = optarg;
break;
case 'c':
setOpts.create = true;
setOpts.createAccount = optarg;
break;
case 'v':
setOpts.value = true;
setOpts.valueAccount = optarg;
break;
case '?':
setOpts.help = true;
setOpts.helpOut = stderr;
break;
default:
break;
}
}
}
void AccountOptHandler::help() {
fprintf(setOpts.helpOut, "Help budget -a {-cvd account|-hl}\n");
fprintf(setOpts.helpOut, " -h --help Output this message.\n");
fprintf(setOpts.helpOut, " -l --list List available accounts.\n");
fprintf(setOpts.helpOut, " -d --delete account Delete the specified account.\n");
fprintf(setOpts.helpOut, " -c --create account Create a new account.\n");
fprintf(setOpts.helpOut, " -v --value account Print the current value of account.\n");
}
const AccountOptHandler::SetOpts *AccountOptHandler::getSetOpts() const {
return &setOpts;
}
AccountOptHandler::AccountOptHandler(const std::vector<char *> &argv) : OptHandler(argv) {}

View File

@ -1,41 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#ifndef BUDGET_ACCOUNTOPTHANDLER_H
#define BUDGET_ACCOUNTOPTHANDLER_H
#include "optHandler.h"
namespace Budget::OptHandlers {
class AccountOptHandler : public OptHandler {
struct SetOpts {
FILE *helpOut = stdout;
bool help = false;
bool list = false;
bool del = false;
char *delAccount{};
bool create = false;
char *createAccount{};
bool value = false;
char *valueAccount{};
};
public:
explicit AccountOptHandler(const std::vector<char *> &argv);
void parse() override;
void help() override;
[[nodiscard]] const SetOpts *getSetOpts() const;
private:
SetOpts setOpts;
};
}
#endif //BUDGET_ACCOUNTOPTHANDLER_H

View File

@ -1,51 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#include <iostream>
#include "mainOptHandler.h"
using namespace Budget::OptHandlers;
MainOptHandler::MainOptHandler(const std::vector<char *> &argv) : OptHandler(argv) {}
void MainOptHandler::parse() {
struct option longOpts[] = {
{"help", no_argument, nullptr, 'h'},
{"account", no_argument, nullptr, 'a'},
};
while (true) {
int opt = getopt_long(getArgc(), getArgv(), "ha", longOpts, nullptr);
if (opt == -1) {
break;
}
switch (opt) {
case 'h':
setOpts.help = true;
break;
case 'a':
setOpts.account = true;
setOpts.accountArgStart = optind - 1;
return;
case '?':
setOpts.help = true;
setOpts.helpOut = stderr;
break;
default:
break;
}
}
}
void MainOptHandler::help() {
fprintf(setOpts.helpOut, "Help budget {-ha}\n");
fprintf(setOpts.helpOut, " -h --help Output this message.\n");
fprintf(setOpts.helpOut, " -a --account Do budget -a -h for more info.\n");
}
const MainOptHandler::SetOpts *MainOptHandler::getSetOpts() const {
return &setOpts;
}

View File

@ -1,33 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#ifndef BUDGET_MAINOPTHANDLER_H
#define BUDGET_MAINOPTHANDLER_H
#include "optHandler.h"
namespace Budget::OptHandlers {
class MainOptHandler : public OptHandler {
struct SetOpts {
FILE *helpOut = stdout;
bool help = false;
bool account = false;
int accountArgStart = -1;
};
public:
explicit MainOptHandler(const std::vector<char *> &argv);
void parse() override;
void help() override;
[[nodiscard]] const SetOpts *getSetOpts() const;
private:
SetOpts setOpts;
};
}
#endif //BUDGET_MAINOPTHANDLER_H

View File

@ -1,20 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#include "optHandler.h"
#include <utility>
using namespace Budget::OptHandlers;
OptHandler::OptHandler(std::vector<char *> argv) : argv(std::move(argv)) {}
int OptHandler::getArgc() {
return argv.size();
}
char **OptHandler::getArgv() {
return argv.data();
}

View File

@ -1,33 +0,0 @@
//
// Created by quentin on 8/13/22.
//
#ifndef BUDGET_OPTHANDLER_H
#define BUDGET_OPTHANDLER_H
#include <getopt.h>
#include <cstdio>
#include <string>
#include <vector>
namespace Budget::OptHandlers {
class OptHandler {
public:
explicit OptHandler(std::vector<char *> argv);
virtual void parse() = 0;
int getArgc();
char **getArgv();
private:
std::vector<char *> argv;
virtual void help() = 0;
};
}
#endif //BUDGET_OPTHANDLER_H

View File

@ -1,97 +0,0 @@
//
// Created by quentin on 9/13/22.
//
#include "math.h"
//Polynomial Fit
#include <iostream>
#include <cmath>
using namespace Budget::Utilities;
PolynomialFunction Math::polynomialFit(int degree, int numberOfPoints, const double x[], const double y[]) {
//Array that will store the values of sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2numberOfPoints)
double X[2 * degree + 1];
for (int i = 0; i < 2 * degree + 1; i++) {
X[i] = 0;
for (int j = 0; j < numberOfPoints; j++) {
//consecutive positions of the array will store numberOfPoints,sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
X[i] = X[i] + pow(x[j], i);
}
}
//B is the Normal matrix(augmented) that will store the equations, 'a' is for value of the final coefficients
double B[degree + 1][degree + 2], a[degree + 1];
for (int i = 0; i <= degree; i++) {
for (int j = 0; j <= degree; j++) {
//Build the Normal matrix by storing the corresponding coefficients at the right positions except the last column of the matrix
B[i][j] = X[i + j];
}
}
//Array to store the values of sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^degree*yi)
double Y[degree + 1];
for (int i = 0; i < degree + 1; i++) {
Y[i] = 0;
for (int j = 0; j < numberOfPoints; j++) {
//consecutive positions will store sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^degree*yi)
Y[i] = Y[i] + pow(x[j], i) * y[j];
}
}
for (int i = 0; i <= degree; i++) {
//load the values of Y as the last column of B(Normal Matrix but augmented)
B[i][degree + 1] = Y[i];
}
//degree is made degree+1 because the Gaussian Elimination part below was for degree equations, but here degree is the degree of polynomial and for degree degree we get degree+1 equations
degree = degree + 1;
//From now Gaussian Elimination starts(can be ignored) to solve the set of linear equations (Pivotisation)
for (int i = 0; i < degree; i++) {
for (int k = i + 1; k < degree; k++) {
if (B[i][i] < B[k][i]) {
for (int j = 0; j <= degree; j++) {
double temp = B[i][j];
B[i][j] = B[k][j];
B[k][j] = temp;
}
}
}
}
//loop to perform the gauss elimination
for (int i = 0; i < degree - 1; i++) {
for (int k = i + 1; k < degree; k++) {
double t = B[k][i] / B[i][i];
for (int j = 0; j <= degree; j++) {
//make the elements below the pivot elements equal to zero or elimnate the variables
B[k][j] = B[k][j] - t * B[i][j];
}
}
}
//back-substitution
for (int i = degree - 1; i >= 0; i--) {
//x is an array whose values correspond to the values of x,y,z..
//make the variable to be calculated equal to the rhs of the last equation
a[i] = B[i][degree];
for (int j = 0; j < degree; j++) {
//then subtract all the lhs values except the coefficient of the variable whose value is being calculated
if (j != i) {
a[i] = a[i] - B[i][j] * a[j];
}
}
//now finally divide the rhs by the coefficient of the variable to be calculated
a[i] = a[i] / B[i][i];
}
std::cout << "\nThe values of the coefficients are as follows:\n";
for (int i = 0; i < degree; i++)
std::cout << "x^" << i << "=" << a[i] << std::endl; // Print the values of x^0,x^1,x^2,x^3,....
std::cout << "\nHence the fitted Polynomial is given by:\ny=";
for (int i = 0; i < degree; i++)
std::cout << " + (" << a[i] << ")" << "x^" << i;
std::cout << "\n";
std::vector<double> va(a, a + degree);
return PolynomialFunction(va);
}

View File

@ -1,19 +0,0 @@
//
// Created by quentin on 9/13/22.
//
#ifndef BUDGET_MATH_H
#define BUDGET_MATH_H
#include "polynomialFunction.h"
namespace Budget::Utilities {
class Math {
public:
static PolynomialFunction polynomialFit(int degree, int numberOfPoints, const double x[], const double y[]);
};
}
#endif //BUDGET_MATH_H

View File

@ -1,21 +0,0 @@
//
// Created by quentin on 9/13/22.
//
#include "polynomialFunction.h"
#include <utility>
#include <cmath>
using namespace Budget::Utilities;
PolynomialFunction::PolynomialFunction(std::vector<double> a) : a(std::move(a)) {}
double PolynomialFunction::get(double x) {
double ret = 0;
for (int i = 0; i < a.size(); ++i) {
ret += a[i] * std::pow(x, i);
}
return ret;
}

View File

@ -1,25 +0,0 @@
//
// Created by quentin on 9/13/22.
//
#ifndef BUDGET_POLYNOMIALFUNCTION_H
#define BUDGET_POLYNOMIALFUNCTION_H
#include <vector>
namespace Budget::Utilities {
class PolynomialFunction {
private:
public:
explicit PolynomialFunction(std::vector<double> a);
double get(double x);
private:
std::vector<double> a;
};
}
#endif //BUDGET_POLYNOMIALFUNCTION_H