diff --git a/CMakeLists.txt b/CMakeLists.txt index 972b11d..704cb0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,9 @@ target_include_directories(mlcpppy PUBLIC ${PROJECT_SOURCE_DIR}/include) # ------------------------------- add_executable(example_main examples/main.cpp) add_executable(example_instance examples/atributes_usage.cpp) +add_executable(example_binary_tree examples/example_binary_tree.cpp) # Linka a biblioteca ao executável target_link_libraries(example_main PRIVATE mlcpppy) target_link_libraries(example_instance PRIVATE mlcpppy) +target_link_libraries(example_binary_tree PRIVATE mlcpppy) diff --git a/examples/atributes_usage.cpp b/examples/atributes_usage.cpp index 79bb9ee..c45f117 100644 --- a/examples/atributes_usage.cpp +++ b/examples/atributes_usage.cpp @@ -1,13 +1,13 @@ #include + #include "mlcpppy/instances/instances.h" -int main(int argc, char const *argv[]) -{ - // Exemplo de uso da classe atribute, instances e instance - Instance a(Attribute(1), Attribute(2.5), Attribute("Pedro")); - Instance b(Attribute(1), Attribute(2.5), Attribute("Pedro")); - Instance c(Attribute(1), Attribute(2.5), Attribute("Pedro")); - Instances matrix({a,b,c}); - std::cout << matrix << std::endl; - return 0; +int main(int argc, char const *argv[]) { + // Exemplo de uso da classe atribute, instances e instance + Instance a(Attribute(1), Attribute(2.5), Attribute("Pedro")); + Instance b(Attribute(1), Attribute(2.5), Attribute("Pedro")); + Instance c(Attribute(1), Attribute(2.5), Attribute("Pedro")); + Instances matrix({a, b, c}); + std::cout << matrix << std::endl; + return 0; } \ No newline at end of file diff --git a/examples/example_binary_tree.cpp b/examples/example_binary_tree.cpp new file mode 100644 index 0000000..0162f56 --- /dev/null +++ b/examples/example_binary_tree.cpp @@ -0,0 +1,28 @@ +#include "mlcpppy/data_structures/binary_tree.h" + +int main(int argc, char const* argv[]) { + BinaryTree* binary_tree = new BinaryTree(); + // Isso deixa desbalanceado + // 20, 8, 22, 4, 12, 10, 14 + + binary_tree->Insert(20); + binary_tree->Insert(8); + binary_tree->Insert(22); + binary_tree->Insert(4); + binary_tree->Insert(12); + binary_tree->Insert(10); + binary_tree->Insert(14); + + binary_tree->TreeSuccessor(); + + binary_tree->Inorder(); + + BinaryTree::Node* busca = binary_tree->Search(8); + if (busca) { + binary_tree->Delete(busca); + } + + binary_tree->Inorder(); + + return 0; +} diff --git a/include/mlcpppy/classifiers/neighbors/kdtree.h b/include/mlcpppy/classifiers/neighbors/kdtree.h index b36405b..004f1f7 100644 --- a/include/mlcpppy/classifiers/neighbors/kdtree.h +++ b/include/mlcpppy/classifiers/neighbors/kdtree.h @@ -17,280 +17,287 @@ #ifndef KDTREE_H #define KDTREE_H -#include -#include #include +#include +#include + #include "nearest_neighbor.h" template class KDTree : public NearestNeighbor { -private: - class Node { - public: - Node* left_; - Node* right_; - Point point_; - int depth_; - - explicit Node() {} - explicit Node(Point point, Node* left, Node* right) : point_(point), left_(left), right_(right) {} - explicit Node(Point point, Node* left, Node* right, int depth) : point_(point), left_(left), right_(right), depth_(depth) {} - explicit Node(Point point) : point_(point) { - this->left_ = nullptr; - this->right_ = nullptr; - } - explicit Node(Point point, int depth) : point_(point), depth_(depth) { - this->left_ = nullptr; - this->right_ = nullptr; + private: + class Node { + public: + Node* left_; + Node* right_; + Point point_; + int depth_; + + explicit Node() {} + explicit Node(Point point, Node* left, Node* right) + : point_(point), left_(left), right_(right) {} + explicit Node(Point point, Node* left, Node* right, + int depth) + : point_(point), + left_(left), + right_(right), + depth_(depth) {} + explicit Node(Point point) : point_(point) { + this->left_ = nullptr; + this->right_ = nullptr; + } + explicit Node(Point point, int depth) + : point_(point), depth_(depth) { + this->left_ = nullptr; + this->right_ = nullptr; + } + + ~Node() { + delete left_; + delete right_; + } + }; + + Node* root_; + int K_; + std::priority_queue> bests_; + + Node* Build(std::vector> points, int depth) { + if (points.empty()) { + return nullptr; + } + int k = points.at(0).data().size(); + int axis = depth % k; + + std::sort(points.begin(), points.end(), + [axis](const Point& a, const Point& b) { + return a.data()[axis] < b.data()[axis]; + }); + + int median = points.size() / 2; + std::vector> points_left(points.begin(), + points.begin() + median); + std::vector> points_right( + points.begin() + median + 1, points.end()); + + return new Node(points.at(median), + Build(points_left, depth + 1), + Build(points_right, depth + 1), depth); } - ~Node() { - delete left_; - delete right_; - } - }; - - Node* root_; - int K_; - std::priority_queue> bests_; - - Node* Build(std::vector> points, int depth) { - if (points.empty()) { - return nullptr; - } - int k = points.at(0).data().size(); - int axis = depth % k; - - std::sort(points.begin(), points.end(), [axis](const Point& a, const Point& b) { - return a.data()[axis] < b.data()[axis]; - }); - - int median = points.size() / 2; - std::vector> points_left(points.begin(), points.begin() + median); - std::vector> points_right(points.begin() + median + 1, points.end()); - - - return new Node( - points.at(median), - Build(points_left, depth + 1), - Build(points_right, depth + 1), - depth - ); - } - + Node* NearestNeighbor(Node* root, Point& target, int depth) { + if (root == nullptr) return nullptr; - Node* NearestNeighbor(Node* root, Point& target, int depth) { - if (root == nullptr) return nullptr; + Node* next_branch; + Node* other_branch; - Node* next_branch; - Node* other_branch; + int axis = depth % root->point_.size(); - int axis = depth % root->point_.size(); + if (target.data().at(axis) < root->point_.data().at(axis)) { + next_branch = root->left_; + other_branch = root->right_; + } else { + next_branch = root->right_; + other_branch = root->left_; + } - if (target.data().at(axis) < root->point_.data().at(axis)) - { - next_branch = root->left_; - other_branch = root->right_; - } else { - next_branch = root->right_; - other_branch = root->left_; - } + Node* temp = NearestNeighbor(next_branch, target, depth + 1); + Node* best = Closest(temp, root, target); + double radius_squared = DistSquared(target, best->point_); - Node* temp = NearestNeighbor(next_branch, target, depth + 1); - Node* best = Closest(temp, root, target); - double radius_squared = DistSquared(target, best->point_); + double dist = + target.data().at(axis) - root->point_.data().at(axis); - double dist = target.data().at(axis) - root->point_.data().at(axis); + if (radius_squared >= dist * dist) { + temp = NearestNeighbor(other_branch, target, depth + 1); + best = Closest(temp, best, target); + } - if (radius_squared >= dist * dist) - { - temp = NearestNeighbor(other_branch, target, depth + 1); - best = Closest(temp, best, target); + return best; } - return best; + void KNearestNeighbor(Node* root, Point& target, int depth) { + if (root == nullptr) return; - } + Node* next_branch; + Node* other_branch; - void KNearestNeighbor(Node* root, Point& target, int depth) { - if (root == nullptr) return; + int axis = depth % root->point_.size(); - Node* next_branch; - Node* other_branch; + if (target.data().at(axis) < root->point_.data().at(axis)) { + next_branch = root->left_; + other_branch = root->right_; + } else { + next_branch = root->right_; + other_branch = root->left_; + } - int axis = depth % root->point_.size(); + KNearestNeighbor(next_branch, target, depth + 1); + double dist = DistSquared(target, root->point_); - if (target.data().at(axis) < root->point_.data().at(axis)) - { - next_branch = root->left_; - other_branch = root->right_; - } else { - next_branch = root->right_; - other_branch = root->left_; - } + if (this->bests_.size() < this->K_) { + this->bests_.push({dist, root}); + } else if (dist < this->bests_.top().first) { + bests_.pop(); + this->bests_.push({dist, root}); + } - KNearestNeighbor(next_branch, target, depth + 1); - double dist = DistSquared(target, root->point_); + double diff = + target.data().at(axis) - root->point_.data().at(axis); - if (this->bests_.size() < this->K_) - { - this->bests_.push({dist, root}); + if (this->bests_.size() < this->K_ || + diff * diff < this->bests_.top().first) { + KNearestNeighbor(other_branch, target, depth + 1); + } } - else if (dist < this->bests_.top().first) - { - bests_.pop(); - this->bests_.push({dist, root}); - } - - double diff = target.data().at(axis) - root->point_.data().at(axis); - - if (this->bests_.size() < this->K_ || diff * diff < this->bests_.top().first) { - KNearestNeighbor(other_branch, target, depth + 1); - } - } - - - Node* Closest(Node* n0, Node* n1, Point& target) { - if (n0 == nullptr) return n1; - if (n1 == nullptr) return n0; - long d1 = DistSquared(n0->point_, target); - long d2 = DistSquared(n1->point_, target); + Node* Closest(Node* n0, Node* n1, Point& target) { + if (n0 == nullptr) return n1; + if (n1 == nullptr) return n0; - if (d1 < d2) - return n0; - else - return n1; - } + long d1 = DistSquared(n0->point_, target); + long d2 = DistSquared(n1->point_, target); - double DistSquared(const Point& p0, const Point& p1) { - long total = 0; - size_t numDims = p0.size(); - - for (size_t i = 0; i < numDims; ++i) { - int diff = std::abs(p0.data()[i] - p1.data()[i]); - total += static_cast(diff) * diff; // mais eficiente que pow para int + if (d1 < d2) + return n0; + else + return n1; } - return total; - } - - static void Inorder(Node* root) { - if (!root) return; - - Inorder(root->left_); + double DistSquared(const Point& p0, const Point& p1) { + long total = 0; + size_t numDims = p0.size(); - if (root->left_) { - std::cout << " \""; - for (size_t i = 0; i < root->point_.size(); i++) - std::cout << root->point_.data()[i] << (i + 1 == root->point_.size() ? "" : ","); - std::cout << "\" -> \""; - for (size_t i = 0; i < root->left_->point_.size(); i++) - std::cout << root->left_->point_.data()[i] << (i + 1 == root->left_->point_.size() ? "" : ","); - std::cout << "\" [label=\"esq\"];\n"; - } + for (size_t i = 0; i < numDims; ++i) { + int diff = std::abs(p0.data()[i] - p1.data()[i]); + total += static_cast(diff) * + diff; // mais eficiente que pow para int + } - if (root->right_) { - std::cout << " \""; - for (size_t i = 0; i < root->point_.size(); i++) - std::cout << root->point_.data()[i] << (i + 1 == root->point_.size() ? "" : ","); - std::cout << "\" -> \""; - for (size_t i = 0; i < root->right_->point_.size(); i++) - std::cout << root->right_->point_.data()[i] << (i + 1 == root->right_->point_.size() ? "" : ","); - std::cout << "\" [label=\"dir\"];\n"; + return total; } - Inorder(root->right_); - } - -public: - KDTree() : root_(nullptr) {} - void Insert(Point point) override { - Node* p = this->root_; - Node* prev = nullptr; - - int depth = 0; - int n_dims = point.size(); - - while (p != nullptr) - { - prev = p; - if (point.data().at(depth) < p->point_.data().at(depth)) - p = p->left_; - else - p= p->right_; - depth = (depth + 1) % n_dims; + static void Inorder(Node* root) { + if (!root) return; + + Inorder(root->left_); + + if (root->left_) { + std::cout << " \""; + for (size_t i = 0; i < root->point_.size(); i++) + std::cout + << root->point_.data()[i] + << (i + 1 == root->point_.size() ? "" + : ","); + std::cout << "\" -> \""; + for (size_t i = 0; i < root->left_->point_.size(); i++) + std::cout + << root->left_->point_.data()[i] + << (i + 1 == root->left_->point_.size() + ? "" + : ","); + std::cout << "\" [label=\"esq\"];\n"; + } + + if (root->right_) { + std::cout << " \""; + for (size_t i = 0; i < root->point_.size(); i++) + std::cout + << root->point_.data()[i] + << (i + 1 == root->point_.size() ? "" + : ","); + std::cout << "\" -> \""; + for (size_t i = 0; i < root->right_->point_.size(); i++) + std::cout + << root->right_->point_.data()[i] + << (i + 1 == root->right_->point_.size() + ? "" + : ","); + std::cout << "\" [label=\"dir\"];\n"; + } + + Inorder(root->right_); } - if (this->root_ == nullptr) - this->root_ = new Node(point); - else if((point.data().at((depth - 1) % n_dims)) < (prev->point_.data().at((depth - 1) % n_dims))) - prev->left_ = new Node(point, depth); - else - prev->right_ = new Node(point, depth); - } - - void BuildTree(std::vector> points) override { - if (points.empty()) - { - return; + public: + KDTree() : root_(nullptr) {} + void Insert(Point point) override { + Node* p = this->root_; + Node* prev = nullptr; + + int depth = 0; + int n_dims = point.size(); + + while (p != nullptr) { + prev = p; + if (point.data().at(depth) < p->point_.data().at(depth)) + p = p->left_; + else + p = p->right_; + depth = (depth + 1) % n_dims; + } + + if (this->root_ == nullptr) + this->root_ = new Node(point); + else if ((point.data().at((depth - 1) % n_dims)) < + (prev->point_.data().at((depth - 1) % n_dims))) + prev->left_ = new Node(point, depth); + else + prev->right_ = new Node(point, depth); } - int initial_size = points.at(0).size(); + void BuildTree(std::vector> points) override { + if (points.empty()) { + return; + } - for (auto &point : points) - { - if (point.data().empty()) - { - return; - } + int initial_size = points.at(0).size(); - if (point.size() != initial_size) - { - return; - } + for (auto& point : points) { + if (point.data().empty()) { + return; + } + if (point.size() != initial_size) { + return; + } + } + this->root_ = Build(points, 0); } - this->root_ = Build(points, 0); - } - - - std::vector> KNearestNeighbor(Point target_points, int k) override { - if (k) - this->K_ = k; - - if (k == 1){ - Node* result = NearestNeighbor(this->root_, target_points, 0); - std::vector> points; - if (result) - { - points.push_back(result->point_); - } - return points; + std::vector> KNearestNeighbor(Point target_points, + int k) override { + if (k) this->K_ = k; + + if (k == 1) { + Node* result = + NearestNeighbor(this->root_, target_points, 0); + std::vector> points; + if (result) { + points.push_back(result->point_); + } + return points; + } + + KNearestNeighbor(this->root_, target_points, 0); + std::vector> tmp; + while (!this->bests_.empty()) { + tmp.push_back(this->bests_.top().second->point_); + this->bests_.pop(); + } + + return tmp; } - KNearestNeighbor(this->root_, target_points, 0); - std::vector> tmp; - while (!this->bests_.empty()) - { - tmp.push_back(this->bests_.top().second->point_); - this->bests_.pop(); + void PrintInorder() { + // TODO: A ideia é isso gerar um arquivo para o graphiz gerar o + // grafo + std::cout << "digraph G {\n"; + Inorder(this->root_); + std::cout << "}\n"; } - return tmp; - } - - void PrintInorder() { - // TODO: A ideia é isso gerar um arquivo para o graphiz gerar o grafo - std::cout << "digraph G {\n"; - Inorder(this->root_); - std::cout << "}\n"; - } - - ~KDTree() override { - delete root_; - } + ~KDTree() override { delete root_; } }; #endif // KDTREE_H \ No newline at end of file diff --git a/include/mlcpppy/classifiers/neighbors/nearest_neighbor.h b/include/mlcpppy/classifiers/neighbors/nearest_neighbor.h index dbb445e..457e77f 100644 --- a/include/mlcpppy/classifiers/neighbors/nearest_neighbor.h +++ b/include/mlcpppy/classifiers/neighbors/nearest_neighbor.h @@ -17,15 +17,16 @@ #ifndef NEAREST_NEIGHBOR_H #define NEAREST_NEIGHBOR_H #include + #include "point.h" -template +template class NearestNeighbor { - public: - virtual ~NearestNeighbor() = default; - virtual std::vector> KNearestNeighbor(Point, int) = 0; - virtual void Insert(Point) = 0; - virtual void BuildTree(std::vector>) = 0; - virtual void Delete(Point){}; + public: + virtual ~NearestNeighbor() = default; + virtual std::vector> KNearestNeighbor(Point, int) = 0; + virtual void Insert(Point) = 0; + virtual void BuildTree(std::vector>) = 0; + virtual void Delete(Point){}; }; #endif // NEAREST_NEIGHBOR_H \ No newline at end of file diff --git a/include/mlcpppy/classifiers/neighbors/point.h b/include/mlcpppy/classifiers/neighbors/point.h index b012019..27ffb8e 100644 --- a/include/mlcpppy/classifiers/neighbors/point.h +++ b/include/mlcpppy/classifiers/neighbors/point.h @@ -40,9 +40,7 @@ class Point { std::copy(list.begin(), list.end(), data_.begin()); } const std::array &data() const { return data_; } - const size_t size() const { - return data_.size(); - } + const size_t size() const { return data_.size(); } }; -#endif // POINT_H \ No newline at end of file +#endif // POINT_H \ No newline at end of file diff --git a/include/mlcpppy/data_structures/b_tree.h b/include/mlcpppy/data_structures/b_tree.h new file mode 100644 index 0000000..e69de29 diff --git a/include/mlcpppy/data_structures/binary_tree.h b/include/mlcpppy/data_structures/binary_tree.h new file mode 100644 index 0000000..d7d6fe8 --- /dev/null +++ b/include/mlcpppy/data_structures/binary_tree.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2025 Pedro Bianchini de Quadros + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +template +class BinaryTree { + public: + class Node { + public: + N key; + Node* left; + Node* right; + Node* p; // -> Refere-se ao pai + + Node(N key) : key(key){}; + }; + + BinaryTree() { this->root = nullptr; }; + + void Insert(N new_key) { + Node* y = nullptr; + Node* x = this->root; + Node* z = new Node(new_key); + + while (x) { + y = x; + if (z->key < x->key) + x = x->left; + else + x = x->right; + } + + // Ponteiro para o pai + z->p = y; + + if (y == nullptr) + this->root = z; + else if (z->key < y->key) + y->left = z; + else + y->right = z; + } + + void Delete(Node* z) { + if (z->left == nullptr) + this->Transplant(z, z->right); + else if (z->right == nullptr) + this->Transplant(z, z->left); + else { + Node* y = Minimum(z->right); + if (y->p != z) { + this->Transplant(y, y->right); + y->right = z->right; + y->right->p = y; + } + + this->Transplant(z, y); + y->left = z->left; + y->left->p = y; + } + } + + void Inorder() const { + InorderRecursive(this->root); + std::cout << std::endl; + } + + Node* Search(N key) { return this->TreeSearch(this->root, key); } + + Node* Minimum(Node* x) const { + while (x->left != nullptr) x = x->left; + return x; + } + + Node* Maximum(Node* x) const { + while (x->right != nullptr) x = x->right; + return x; + } + + Node* TreeSuccessor(Node* x) const { + if (x->right) return Minimum(x->right); + + // O y vai receber o pai do x + Node* y = x->p; + while (y && x == y->right) { + x = y; + y = y->p; + } + + return y; + } + + Node* TreePredecessor(Node* x) const { + if (x->left) return Maximum(x->left); + + // O y vai receber o pai do x + Node* y = x->p; + while (y && x == y->left) { + x = y; + y = y->p; + } + + return y; + } + + Node* TreeSuccessor() { return TreeSuccessor(this->root); } + + ~BinaryTree() = default; + + private: + Node* root; + + void InorderRecursive(Node* root) const { + if (root) { + InorderRecursive(root->left); + std::cout << root->key << std::endl; + std::cout << "Pai: "; + if (root->p) { + std::cout << root->p->key << std::endl; + } else { + std::cout << "Sem pai" << std::endl; + } + InorderRecursive(root->right); + } + } + + Node* TreeSearch(Node* root, N k) { + if (root == nullptr || k == root->key) { + return root; + } + + if (k < root->key) return TreeSearch(root->left, k); + return TreeSearch(root->right, k); + } + + void Transplant(Node* u, Node* v) { + if (u->p == nullptr) + this->root = v; + else if (u == u->p->left) + u->p->left = v; + else + u->p->right = v; + + if (v) v->p = u->p; + } +}; \ No newline at end of file diff --git a/include/mlcpppy/data_structures/rb_tree.h b/include/mlcpppy/data_structures/rb_tree.h new file mode 100644 index 0000000..589ae71 --- /dev/null +++ b/include/mlcpppy/data_structures/rb_tree.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2025 Pedro Bianchini de Quadros + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +template +class RBTree { + private: + class Node { + public: + Node* left; + Node* right; + Node* parent; + N value; + int color; + + explict Node(N value) : value(value) { + this->left = nullptr; + this->right = nullptr; + this->parent = nullptr; + } + } + + Node* root; + constexpr int BLACK = 0; + constexpr int RED = 1; + + public: + void Insert() {} + + void Remove() {} + + Node Search() const {} + + int Color(Node* node) { + if (node != nullptr) { + return this->BLACK; + } else { + return node->color; + } + } + + void ChangeColor(Node* node) { + node->color = !node->color; + if (node->left) node->left->color = !node->left->color; + + if (node->right) node->right->color = !node->right->color; + } + + Node* RotateLeft(Node* A) { + Node* B = A->right; + A->right = B->left; + B->left = A; + B->color = A->color; + A->color = this->RED; + return B; + } + + Node* RotateRight(Node* A) { + Node* B = A->left; + A->left = B->right; + B->right = A; + B->color = A->color; + A->color = this->RED; + return B; + } + + Node* MoveToLeftRed(Node* node) { + this->ChangeColor(node); + if (this->Color(node->right->left) == this->RED) { + node->right = this->RotateRight(node->right); + node = this->RotateLeft(node); + this->ChangeColor(node); + } + } + + Node* MoveToRightRed(Node* node) { + this->ChangeColor(node); + if (this->Color(node->left->left) == this->RED) { + node = this->RotateRight(node); + this->ChangeColor(node); + } + } + + Node* BalanceTree(Node* node) { + if (this->Color(node->right) == this->RED) + node = this->RotateLeft(node); + + if (node->left != nullptr && + this->Color(node->right) == this->RED && + this->Color(node->left->left) == this->RED) + node = this->RotateLeft(node); + + if (this->Color(node->left) == this->RED && + this->Color(node->right) == this->RED) + this->ChangeColor(node); + + return node; + } +}; diff --git a/include/mlcpppy/instances/attribute.h b/include/mlcpppy/instances/attribute.h index adeacad..2af0ca2 100644 --- a/include/mlcpppy/instances/attribute.h +++ b/include/mlcpppy/instances/attribute.h @@ -17,64 +17,71 @@ #ifndef ATTRIBUTE_H #define ATTRIBUTE_H +#include #include #include #include -#include /** * @brief Represents a single attribute that can hold multiple types of values. - * + * * @note This class is still under development. Future features may include - * better type introspection, validation, and integration with Instances and ARFF loading. + * better type introspection, validation, and integration with Instances + * and ARFF loading. */ -class Attribute -{ -public: - using ValueType = std::variant; ///< Supported types for the attribute +class Attribute { + public: + using ValueType = + std::variant; ///< Supported types for the attribute - /** - * @brief Constructs an Attribute with an int value. - * @param v The integer value to store. - */ - Attribute(int v) : value(v) {} + /** + * @brief Constructs an Attribute with an int value. + * @param v The integer value to store. + */ + Attribute(int v) : value(v) {} - /** - * @brief Constructs an Attribute with a double value. - * @param v The double value to store. - */ - Attribute(double v) : value(v) {} + /** + * @brief Constructs an Attribute with a double value. + * @param v The double value to store. + */ + Attribute(double v) : value(v) {} - /** - * @brief Constructs an Attribute with a string value. - * @param v The string value to store. - */ - Attribute(const std::string& v) : value(v) {} + /** + * @brief Constructs an Attribute with a string value. + * @param v The string value to store. + */ + Attribute(const std::string& v) : value(v) {} - /** - * @brief Returns a constant reference to the stored value. - * @return The stored value as a ValueType. - */ - const ValueType& GetValue() const { return value; } + /** + * @brief Returns a constant reference to the stored value. + * @return The stored value as a ValueType. + */ + const ValueType& GetValue() const { return value; } - /** - * @brief Overloads the stream insertion operator to print the attribute value and type. - * @param os Output stream. - * @param a The Attribute object to print. - * @return Reference to the output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const Attribute& a) { - std::visit([&os](auto&& arg) { os << arg << "(" << typeid(arg).name() << ")"; }, a.GetValue()); - return os; - } + /** + * @brief Overloads the stream insertion operator to print the attribute + * value and type. + * @param os Output stream. + * @param a The Attribute object to print. + * @return Reference to the output stream. + */ + friend std::ostream& operator<<(std::ostream& os, const Attribute& a) { + std::visit( + [&os](auto&& arg) { + os << arg << "(" << typeid(arg).name() << ")"; + }, + a.GetValue()); + return os; + } - /** - * @brief Default destructor. - */ - ~Attribute() = default; + /** + * @brief Default destructor. + */ + ~Attribute() = default; -private: - ValueType value; ///< Internal storage for the attribute's value + private: + ValueType value; ///< Internal storage for the attribute's value }; -#endif // ATTRIBUTE_H \ No newline at end of file +#endif // ATTRIBUTE_H \ No newline at end of file diff --git a/include/mlcpppy/instances/instance.h b/include/mlcpppy/instances/instance.h index c0fece6..c128734 100644 --- a/include/mlcpppy/instances/instance.h +++ b/include/mlcpppy/instances/instance.h @@ -17,48 +17,55 @@ #ifndef INSTANCE_H #define INSTANCE_H -#include #include +#include + #include "attribute.h" /** * @brief Represents a single instance consisting of multiple Attribute objects. - * + * * @note This class is still under development. Future features may include * schema validation, type checking, and integration with ARFF datasets. */ -class Instance -{ -private: - std::vector values_instance_; ///< Container for the attributes of this instance +class Instance { + private: + std::vector + values_instance_; ///< Container for the attributes of this + ///< instance -public: - /** - * @brief Constructs an Instance with a variable number of Attribute arguments. - * - * @tparam Args Variadic template parameter representing Attribute types. - * @param args Attributes to include in this instance. - */ - template - Instance(Args... args) { - values_instance_ = {args...}; - } + public: + /** + * @brief Constructs an Instance with a variable number of Attribute + * arguments. + * + * @tparam Args Variadic template parameter representing Attribute + * types. + * @param args Attributes to include in this instance. + */ + template + Instance(Args... args) { + values_instance_ = {args...}; + } - /** - * @brief Overloads the stream insertion operator to print all attributes in the instance. - * @param os Output stream. - * @param inst The Instance object to print. - * @return Reference to the output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const Instance& inst) { - os << "["; - for (size_t i = 0; i < inst.values_instance_.size(); ++i) { - os << inst.values_instance_[i]; - if (i != inst.values_instance_.size() - 1) os << ", "; // Comma between elements + /** + * @brief Overloads the stream insertion operator to print all + * attributes in the instance. + * @param os Output stream. + * @param inst The Instance object to print. + * @return Reference to the output stream. + */ + friend std::ostream& operator<<(std::ostream& os, + const Instance& inst) { + os << "["; + for (size_t i = 0; i < inst.values_instance_.size(); ++i) { + os << inst.values_instance_[i]; + if (i != inst.values_instance_.size() - 1) + os << ", "; // Comma between elements + } + os << "]"; + return os; } - os << "]"; - return os; - } }; -#endif // INSTANCE_H \ No newline at end of file +#endif // INSTANCE_H \ No newline at end of file diff --git a/include/mlcpppy/instances/instances.h b/include/mlcpppy/instances/instances.h index 9d900c2..e2eaf32 100644 --- a/include/mlcpppy/instances/instances.h +++ b/include/mlcpppy/instances/instances.h @@ -18,46 +18,53 @@ #define INSTANCES_H #include + #include "instance.h" /** - * @brief Represents a collection of Instance objects, similar to a dataset in ARFF format. - * + * @brief Represents a collection of Instance objects, similar to a dataset in + * ARFF format. + * * @note This class is still under development. Future features may include * schema validation, type checking, and ARFF file loading. */ -class Instances -{ -private: - std::vector instances_data_; ///< Container for all Instance objects +class Instances { + private: + std::vector + instances_data_; ///< Container for all Instance objects -public: - /** - * @brief Constructor that initializes the Instances collection. - * @param instances Vector of Instance objects to initialize the collection. - */ - Instances(std::vector instances) : instances_data_(instances) {} + public: + /** + * @brief Constructor that initializes the Instances collection. + * @param instances Vector of Instance objects to initialize the + * collection. + */ + Instances(std::vector instances) + : instances_data_(instances) {} - /** - * @brief Overloads the stream insertion operator to print all instances. - * @param os Output stream. - * @param instances The Instances object to print. - * @return Reference to the output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const Instances& instances) { - os << "["; - for (size_t i = 0; i < instances.instances_data_.size(); ++i) { - os << instances.instances_data_[i]; - if (i != instances.instances_data_.size() - 1) os << ", \n"; // Comma between elements + /** + * @brief Overloads the stream insertion operator to print all + * instances. + * @param os Output stream. + * @param instances The Instances object to print. + * @return Reference to the output stream. + */ + friend std::ostream& operator<<(std::ostream& os, + const Instances& instances) { + os << "["; + for (size_t i = 0; i < instances.instances_data_.size(); ++i) { + os << instances.instances_data_[i]; + if (i != instances.instances_data_.size() - 1) + os << ", \n"; // Comma between elements + } + os << "]"; + return os; } - os << "]"; - return os; - } - /** - * @brief Default destructor. - */ - ~Instances() = default; + /** + * @brief Default destructor. + */ + ~Instances() = default; }; -#endif // INSTANCES_H \ No newline at end of file +#endif // INSTANCES_H \ No newline at end of file