Skip to content

Commit 85247b3

Browse files
authored
feat: Add math module with number theory algorithms and code quality tooling (#15)
This pull request introduces a new math module to the project, adding implementations for several number theory algorithms, and enhances the build system by integrating code quality tools. It also makes minor formatting improvements to existing graph and search code for consistency. **New Math Algorithms:** * Added new math module (`src/math/`) with implementations for: - Extended Euclidean Algorithm (recursive and iterative), GCD, LCM, modular inverse (via Extended GCD), and related utilities in `extended_gcd.hpp` - Fast exponentiation (with and without modulo), modular inverse via Fermat’s Little Theorem in `fast_exp.hpp` - Sieve of Eratosthenes and related prime utilities in `sieve.hpp` * Updated `CMakeLists.txt` to include new math sources and tests [[1]](diffhunk://#diff-1e7de1ae2d059d21e1dd75d5812d5a34b0222cef273b7c3a2af62eb747f9d20aR23) [[2]](diffhunk://#diff-1e7de1ae2d059d21e1dd75d5812d5a34b0222cef273b7c3a2af62eb747f9d20aR32) **Build System and Code Quality:** * Added code quality tooling to `CMakeLists.txt`: - Targets for `clang-format` (formatting and format-check) - Target for `clang-tidy` (linting) - Automatically collects all source and test files for these tools **Code Formatting and Style Consistency:** * Refactored several methods in graph algorithms (`bfs.hpp`, `dfs.hpp`, `kruskal.hpp`) to use single-line definitions for trivial functions, improving code consistency [[1]](diffhunk://#diff-3a4b361bf3976e77f349511ff7128ffa95605dd1f7439bf60d13a5c71a42b25dL26-R26) [[2]](diffhunk://#diff-8e68f308a036639d8ef3c8d27b1d42015f92db971daba5e31fc26fd9acff1e40L26-R26) [[3]](diffhunk://#diff-2cf88c17b45aaab80a3a46e62ee7e698ad0a621a513f96e8c5283467eada8e43L18-R18) [[4]](diffhunk://#diff-2cf88c17b45aaab80a3a46e62ee7e698ad0a621a513f96e8c5283467eada8e43L120-R118) [[5]](diffhunk://#diff-8e68f308a036639d8ef3c8d27b1d42015f92db971daba5e31fc26fd9acff1e40L103-R102) * Improved comment formatting in binary search utilities for readability (`binary_search.hpp`) [[1]](diffhunk://#diff-a3fbb7e77fc266ed86ac6d96d669c727b8d1c328c30d1db10b48c44c66a8094aL46-R47) [[2]](diffhunk://#diff-a3fbb7e77fc266ed86ac6d96d669c727b8d1c328c30d1db10b48c44c66a8094aL101-R103)
1 parent 7c3e098 commit 85247b3

25 files changed

+757
-69
lines changed

CMakeLists.txt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ file(GLOB CORE_SOURCES
2020
src/graph/*.hpp
2121
src/data_structure/*.hpp
2222
src/sorting/*.hpp
23+
src/math/*.hpp
2324
)
2425

2526
# Collect test files
@@ -28,6 +29,7 @@ file(GLOB TEST_SOURCES
2829
tests/graph/*.cpp
2930
tests/data_structure/*.cpp
3031
tests/sorting/*.cpp
32+
tests/math/*.cpp
3133
)
3234

3335
# Combine all sources
@@ -57,3 +59,53 @@ target_link_libraries(clavis_algorithm_test clavis_algorithm GTest::GTest GTest:
5759

5860
# Register test
5961
add_test(NAME AlgorithmTest COMMAND clavis_algorithm_test)
62+
63+
# =============================================================================
64+
# Code Quality Tools
65+
# =============================================================================
66+
67+
# Collect all C++ files for formatting/linting
68+
file(GLOB_RECURSE ALL_CXX_FILES
69+
${CMAKE_SOURCE_DIR}/src/*.hpp
70+
${CMAKE_SOURCE_DIR}/src/*.cpp
71+
${CMAKE_SOURCE_DIR}/src/*.h
72+
${CMAKE_SOURCE_DIR}/tests/*.cpp
73+
)
74+
75+
# clang-format targets
76+
find_program(CLANG_FORMAT clang-format
77+
HINTS
78+
/opt/homebrew/opt/llvm/bin
79+
/usr/local/opt/llvm/bin
80+
)
81+
if(CLANG_FORMAT)
82+
add_custom_target(format
83+
COMMAND ${CLANG_FORMAT} -i ${ALL_CXX_FILES}
84+
COMMENT "Running clang-format on all files"
85+
VERBATIM
86+
)
87+
88+
add_custom_target(format-check
89+
COMMAND ${CLANG_FORMAT} --dry-run --Werror ${ALL_CXX_FILES}
90+
COMMENT "Checking code format"
91+
VERBATIM
92+
)
93+
else()
94+
message(STATUS "clang-format not found. Format targets disabled.")
95+
endif()
96+
97+
# clang-tidy target
98+
find_program(CLANG_TIDY clang-tidy
99+
HINTS
100+
/opt/homebrew/opt/llvm/bin
101+
/usr/local/opt/llvm/bin
102+
)
103+
if(CLANG_TIDY)
104+
add_custom_target(lint
105+
COMMAND ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} ${ALL_CXX_FILES}
106+
COMMENT "Running clang-tidy"
107+
VERBATIM
108+
)
109+
else()
110+
message(STATUS "clang-tidy not found. Lint target disabled.")
111+
endif()

src/data_structure/binary_search_tree.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ concept Comparable = std::totally_ordered<T> && std::copyable<T>;
1414

1515
template <Comparable T>
1616
class BinarySearchTree {
17-
private:
17+
private:
1818
struct Node {
1919
T value;
2020
std::unique_ptr<Node> left;
@@ -25,7 +25,7 @@ class BinarySearchTree {
2525
std::unique_ptr<Node> root;
2626
size_t nodeCount = 0;
2727

28-
public:
28+
public:
2929
BinarySearchTree() = default;
3030

3131
void insert(const T& value) {

src/data_structure/fenwick_tree.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// Fenwick Tree (Binary Indexed Tree) for handling
88
// prefix sums over a 1D array with point updates.
99
class FenwickTree {
10-
public:
10+
public:
1111
explicit FenwickTree(std::size_t n) : size_(n), fenw_(n + 1, 0) {}
1212

1313
// Add 'delta' to element at index 'idx'
@@ -48,7 +48,7 @@ class FenwickTree {
4848
return query(right) - (left == 0 ? 0 : query(left - 1));
4949
}
5050

51-
private:
51+
private:
5252
std::size_t size_;
5353
std::vector<int> fenw_;
5454
};

src/data_structure/max_heap.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// This class provides the main operations of a max-heap.
99
template <typename T>
1010
class MaxHeap {
11-
public:
11+
public:
1212
MaxHeap() = default;
1313

1414
// Insert a new value into the heap
@@ -49,7 +49,7 @@ class MaxHeap {
4949
// Returns the number of elements in the heap
5050
std::size_t size() const { return data_.size(); }
5151

52-
private:
52+
private:
5353
std::vector<T> data_;
5454

5555
// Restore the heap property by moving the element at index 'idx'

src/data_structure/segment_tree.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
template <typename T>
1414
class SegmentTree {
15-
private:
15+
private:
1616
int n; // Number of leaves
1717
std::vector<T> tree; // Container to store the segment tree
1818
std::function<T(T, T)> op; // Binary operation to merge intervals
@@ -34,7 +34,7 @@ class SegmentTree {
3434
}
3535
}
3636

37-
public:
37+
public:
3838
/**
3939
* @brief Constructor
4040
*

src/data_structure/union_find.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ template <typename T>
1111
concept Integral = std::is_integral_v<T>;
1212

1313
class UnionFind {
14-
private:
14+
private:
1515
std::vector<int> parent;
1616
std::vector<int> rank;
1717
int groupCount;
@@ -20,7 +20,7 @@ class UnionFind {
2020
return x >= 0 && static_cast<size_t>(x) < parent.size();
2121
}
2222

23-
public:
23+
public:
2424
explicit UnionFind(size_t size)
2525
: parent(size), rank(size, 0), groupCount(static_cast<int>(size)) {
2626
std::iota(parent.begin(), parent.end(), 0);

src/graph/bfs.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ concept HashableNode = GraphNode<T> && requires(T x) {
1919

2020
template <HashableNode NodeType>
2121
class BFS {
22-
private:
22+
private:
2323
using Graph = std::unordered_map<NodeType, std::vector<NodeType>>;
2424
Graph adjacencyList;
2525

26-
void logVisit(const NodeType& node) const {
27-
std::cout << "Visiting node: " << node << std::endl;
28-
}
26+
void logVisit(const NodeType& node) const { std::cout << "Visiting node: " << node << std::endl; }
2927

30-
public:
28+
public:
3129
void addEdge(const NodeType& from, const NodeType& to) {
3230
adjacencyList[from].push_back(to);
3331
// In the case of an isolated point, create an empty adjacent list

src/graph/dfs.hpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ concept HashableNode = GraphNode<T> && requires(T x) {
1919

2020
template <HashableNode NodeType>
2121
class DFS {
22-
private:
22+
private:
2323
using Graph = std::unordered_map<NodeType, std::vector<NodeType>>;
2424
Graph adjacencyList;
2525

26-
void logVisit(const NodeType& node) const {
27-
std::cout << "Visiting node: " << node << std::endl;
28-
}
26+
void logVisit(const NodeType& node) const { std::cout << "Visiting node: " << node << std::endl; }
2927

3028
// Helper function for recursive DFS traversal
3129
void traverseRecursive(const NodeType& node, std::unordered_map<NodeType, bool>& visited,
@@ -44,7 +42,7 @@ class DFS {
4442
}
4543
}
4644

47-
public:
45+
public:
4846
void addEdge(const NodeType& from, const NodeType& to) {
4947
adjacencyList[from].push_back(to);
5048
// In the case of an isolated point, create an empty adjacent list
@@ -100,7 +98,8 @@ class DFS {
10098
}
10199

102100
// Find path using DFS (not necessarily the shortest)
103-
[[nodiscard]] std::vector<NodeType> findPath(const NodeType& start, const NodeType& target) const {
101+
[[nodiscard]] std::vector<NodeType> findPath(const NodeType& start,
102+
const NodeType& target) const {
104103
std::stack<NodeType> stack;
105104
std::unordered_map<NodeType, bool> visited;
106105
std::unordered_map<NodeType, NodeType> parent;
@@ -161,7 +160,7 @@ class DFS {
161160
return false;
162161
}
163162

164-
private:
163+
private:
165164
bool hasCycleUtil(const NodeType& node, std::unordered_map<NodeType, bool>& visited,
166165
std::unordered_map<NodeType, bool>& inStack) const {
167166
visited[node] = true;
@@ -184,7 +183,7 @@ class DFS {
184183
return false;
185184
}
186185

187-
public:
186+
public:
188187
// Topological sort (only works for DAGs)
189188
[[nodiscard]] std::vector<NodeType> topologicalSort() const {
190189
if (hasCycle()) {
@@ -210,9 +209,9 @@ class DFS {
210209
return result;
211210
}
212211

213-
private:
212+
private:
214213
void topologicalSortUtil(const NodeType& node, std::unordered_map<NodeType, bool>& visited,
215-
std::stack<NodeType>& stack) const {
214+
std::stack<NodeType>& stack) const {
216215
visited[node] = true;
217216

218217
if (auto it = adjacencyList.find(node); it != adjacencyList.end()) {
@@ -227,7 +226,7 @@ class DFS {
227226
stack.push(node);
228227
}
229228

230-
public:
229+
public:
231230
[[nodiscard]] size_t countConnectedComponents() const {
232231
std::unordered_set<NodeType> unvisited;
233232
for (const auto& [node, _] : adjacencyList) {

src/graph/kruskal.hpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,18 @@ struct KruskalEdge {
1515
long long weight;
1616

1717
// Operator for sorting edges by weight
18-
bool operator<(const KruskalEdge& other) const {
19-
return weight < other.weight;
20-
}
18+
bool operator<(const KruskalEdge& other) const { return weight < other.weight; }
2119
};
2220

2321
/**
2422
* @brief Disjoint Set Union (DSU) data structure for Kruskal's algorithm
2523
*/
2624
class DisjointSet {
27-
private:
25+
private:
2826
std::vector<int> parent;
2927
std::vector<int> rank;
3028

31-
public:
29+
public:
3230
/**
3331
* @brief Initialize a DSU with n elements
3432
* @param n Number of elements
@@ -117,8 +115,6 @@ std::pair<std::vector<KruskalEdge>, long long> kruskal(int n, std::vector<Kruska
117115
* @param mst The MST edges
118116
* @return True if the graph is connected, false otherwise
119117
*/
120-
bool isConnected(int n, const std::vector<KruskalEdge>& mst) {
121-
return mst.size() == n - 1;
122-
}
118+
bool isConnected(int n, const std::vector<KruskalEdge>& mst) { return mst.size() == n - 1; }
123119

124120
#endif // KRUSKAL_HPP

0 commit comments

Comments
 (0)