From 58428fdb914d98b420fb130c37f2bc61408abdca Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 12:52:06 +0000 Subject: [PATCH] Docs: Comprehensive project documentation update This commit includes extensive updates to the project's documentation: 1. **README.md**: * I verified and updated the "Features" section to accurately reflect current library capabilities, distinguishing between the old API and the new `BmpTool` API. * I clarified "Dependencies" and "Core Modules" sections. * I improved the `BmpTool` API explanation and replaced the example with a more comprehensive one from `main.cpp`, demonstrating a full load-process-save cycle. * I updated "Building the Project" with more detailed instructions and clarified test execution. * I added a "Code Documentation" section explaining Doxygen usage for `include/bitmap.hpp` and providing instructions for local documentation generation. * I added a "Contributing" section with basic guidelines. 2. **src/matrix/Documentation/Matrix.MD**: * I performed a thorough review and update to align with `src/matrix/matrix.h`. * I corrected descriptions for iterator template parameters, operator behaviors, and const-correctness. * I documented previously undocumented constructors, destructors, assignment operators, and member functions for `MatrixRow` and `Matrix`. * I updated function signatures, return types (e.g., for in-place methods and compound assignment operators), and parameter types to match the current implementation. * I clarified differences between `at()` (bounds-checked) and `operator[]` (no bounds-checking). * I revised the "Potential Improvements" section to reflect implemented features and add new suggestions. * I updated usage examples. 3. **CHANGELOG.md**: * I added entries under version 0.3.0 to record the significant updates made to `README.md` and `src/matrix/Documentation/Matrix.MD`. These changes ensure that the project documentation is current, accurate, and provides comprehensive guidance for you and contributors. --- CHANGELOG.md | 3 + README.md | 220 ++++++++++++++++++----------- src/matrix/Documentation/Matrix.MD | 186 ++++++++++++++---------- 3 files changed, 255 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 089440c..5ca6ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ All notable changes to this project will be documented in this file. ### Changed - The `bitmap` library now exposes the `BmpTool` API via `include/bitmap.hpp` for simplified bitmap operations. +- **Documentation**: + - Reviewed and significantly updated `README.md` for accuracy regarding features, API examples (old vs. new), build instructions, and added "Code Documentation" and "Contributing" sections. + - Reviewed and extensively updated `src/matrix/Documentation/Matrix.MD` to align with the current `src/matrix/matrix.h` implementation, including documenting move semantics, new functions, and correcting outdated information. ## [0.2.0] - 2024-07-27 diff --git a/README.md b/README.md index 4165780..d88b243 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ The library supports the following image manipulation functions: * **Color Adjustments:** * Greyscale Conversion - * Brightness Adjustment (Overall and per R,G,B,Magenta,Yellow,Cyan channel) - * Contrast Adjustment (Overall and per R,G,B,Magenta,Yellow,Cyan channel) + * Brightness Adjustment (Overall) + * Contrast Adjustment (Overall) * Saturation Adjustment (Overall and per R,G,B,Magenta,Yellow,Cyan channel) * Luminance Adjustment (per R,G,B,Magenta,Yellow,Cyan channel) * Invert Colors @@ -19,76 +19,98 @@ The library supports the following image manipulation functions: * Box Blur * **Geometric Transformations:** * Shrink Image (reduce size) - * Rotate Image (Clockwise and Counter-Clockwise) + * Rotate Image (90 degrees Clockwise and Counter-Clockwise) * Mirror Image (horizontal flip) * Flip Image (vertical flip) -* **Utility:** +* **Utility (Old API - `src/bitmap/bitmap.h`):** * Screen Capture (Windows only: `ScreenShotWindow`) - * Load BMP from file - * Save BMP to file + * Load BMP from file (`Bitmap::File::Open`) + * Save BMP to file (`Bitmap::File::SaveAs`) +* **Utility (New API - `include/bitmap.hpp`):** + * Load BMP from memory (`BmpTool::load`) + * Save BMP to memory (`BmpTool::save`) + +Note: The old API (`src/bitmap/bitmap.h` and `src/bitmapfile/bitmap_file.h`) provides file-based loading/saving and additional pixel-level operations. The new `BmpTool` API (`include/bitmap.hpp`) focuses on memory span-based operations and provides a more modern interface for whole-image manipulations. ## Dependencies -This library utilizes: -* A simple Matrix library (from `src/matrix`) -* A BMP file handling library (from `src/bitmapfile`) -These are now part of the main source tree under the `src/` directory. +This library has internal dependencies: +* A simple Matrix library (from `src/matrix`) used by the old API. +* BMP file handling structures (from `src/bitmapfile`) used by both APIs. +These are part of the main source tree under the `src/` directory. No external libraries are required for core functionality. ## Core Modules -* **Bitmap Library (`src/bitmap`)**: Provides core image processing functions. -* **Bitmap File Handler (`src/bitmapfile`)**: Handles loading and saving of BMP files. -* **Matrix Library (`src/matrix`)**: A generic matrix manipulation library used by the bitmap processing functions. +* **New Bitmap API (`include/bitmap.hpp`)**: Provides the `BmpTool` namespace for modern, span-based image processing. This is the recommended API for new projects. +* **Old Bitmap Library (`src/bitmap`)**: Provides older image processing functions using the `Bitmap::File` class. +* **Bitmap File Handler (`src/bitmapfile`)**: Contains structures and functions for handling BMP file headers and low-level data, used by both APIs. +* **Matrix Library (`src/matrix`)**: A generic matrix manipulation library, primarily used by the old bitmap library. ## New Span-Based API (`BmpTool`) -For more direct memory-based operations and a stable interface, the `BmpTool` API is provided. +For more direct memory-based operations and a stable interface, the `BmpTool` API is provided. This API operates on image data in memory buffers (`std::span`). The main header for this API is `include/bitmap.hpp`. Core components include: -* `BmpTool::Bitmap`: A struct holding image dimensions (width, height, bits-per-pixel) and a `std::vector` for RGBA pixel data. -* `BmpTool::load()`: Loads BMP data from a `std::span` into a `BmpTool::Bitmap`. -* `BmpTool::save()`: Saves a `BmpTool::Bitmap` to a `std::span`. -* `BmpTool::Result`: Used for functions that can return a value or an error, with `BmpTool::BitmapError` providing specific error codes. +* `BmpTool::Bitmap`: A struct holding image dimensions (width, height, bits-per-pixel) and a `std::vector` for pixel data (typically RGBA). +* `BmpTool::load(std::span bmp_data)`: Loads BMP data from a memory span into a `BmpTool::Bitmap`. +* `BmpTool::save(const BmpTool::Bitmap& bitmap, std::span out_bmp_buffer)`: Saves a `BmpTool::Bitmap` to a memory span. The size of the output BMP data can be determined from the `bfSize` field of the `BITMAPFILEHEADER` written to the beginning of the `out_bmp_buffer`. +* `BmpTool::Result`: Used by functions to return either a value `T` or a `BmpTool::BitmapError` enum, indicating the outcome of the operation. For functions that don't return a value on success (like `save`), `BmpTool::Result` is used (internally represented as `Result`). + +All image manipulation functions in the `BmpTool` namespace (e.g., `BmpTool::greyscale`, `BmpTool::shrink`) take a `const BmpTool::Bitmap&` as input and return a `BmpTool::Result`. ### `BmpTool` API Usage Example +The following example demonstrates loading a BMP file into a buffer, processing it using `BmpTool`, and saving the result. This example is a simplified version of `main.cpp`. + ```cpp -#include "include/bitmap.hpp" // Public API +#include "include/bitmap.hpp" // Public API for BmpTool +#include "src/bitmapfile/bitmap_file.h" // For BITMAPFILEHEADER definition (to get actual size) + #include -#include // For reading/writing files to/from buffer for example -#include +#include // For std::ifstream, std::ofstream +#include // For std::cerr, std::cout +#include // For std::memcpy if reading header manually // Helper to read a file into a vector std::vector read_file_to_buffer(const std::string& filepath) { std::ifstream file(filepath, std::ios::binary | std::ios::ate); - if (!file) return {}; + if (!file) { + std::cerr << "Failed to open " << filepath << std::endl; + return {}; + } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); - std::vector buffer(size); + std::vector buffer(static_cast(size)); if (file.read(reinterpret_cast(buffer.data()), size)) { return buffer; } + std::cerr << "Failed to read " << filepath << std::endl; return {}; } -// Helper to write a buffer to a file +// Helper to write a buffer of a specific size to a file bool write_buffer_to_file(const std::string& filepath, const std::vector& buffer, size_t actual_size) { std::ofstream file(filepath, std::ios::binary); - if (!file) return false; + if (!file) { + std::cerr << "Failed to open " << filepath << " for writing." << std::endl; + return false; + } file.write(reinterpret_cast(buffer.data()), actual_size); return file.good(); } int main() { - // Load an existing BMP into a buffer - std::vector input_bmp_data = read_file_to_buffer("input.bmp"); + const std::string input_filename = "input.bmp"; + const std::string output_filename = "output_processed.bmp"; + + // 1. Load an existing BMP into a buffer + std::vector input_bmp_data = read_file_to_buffer(input_filename); if (input_bmp_data.empty()) { - std::cerr << "Failed to read input.bmp into buffer." << std::endl; return 1; } - // Use BmpTool::load + // 2. Use BmpTool::load to parse the buffer BmpTool::Result load_result = BmpTool::load(input_bmp_data); if (load_result.isError()) { @@ -96,48 +118,50 @@ int main() { return 1; } BmpTool::Bitmap my_bitmap = load_result.value(); - std::cout << "Loaded input.bmp into BmpTool::Bitmap: " + std::cout << "Loaded '" << input_filename << "': " << my_bitmap.w << "x" << my_bitmap.h << " @ " << my_bitmap.bpp << "bpp" << std::endl; - // (Perform some manipulation on my_bitmap.data if desired) - // For example, invert the red channel for all pixels: - // for (size_t i = 0; i < my_bitmap.data.size(); i += 4) { - // my_bitmap.data[i] = 255 - my_bitmap.data[i]; // Invert Red - // } + // 3. Perform some manipulation (e.g., greyscale) + BmpTool::Result greyscale_result = BmpTool::greyscale(my_bitmap); + if(greyscale_result.isError()){ + std::cerr << "BmpTool::greyscale failed: " << static_cast(greyscale_result.error()) << std::endl; + return 1; + } + my_bitmap = greyscale_result.value(); // Update bitmap with processed one + std::cout << "Applied greyscale." << std::endl; - // Prepare a buffer for saving - // Estimate required size: headers (54) + data (W*H*4) - size_t estimated_output_size = 54 + my_bitmap.w * my_bitmap.h * 4; - std::vector output_bmp_buffer(estimated_output_size); + // 4. Prepare a buffer for saving. It must be large enough. + // Max possible size: BMP headers (54 bytes) + data (Width * Height * 4 bytes/pixel for 32bpp RGBA) + size_t max_output_size = 54 + my_bitmap.w * my_bitmap.h * 4; + std::vector output_bmp_buffer(max_output_size); - // Use BmpTool::save + // 5. Use BmpTool::save BmpTool::Result save_result = BmpTool::save(my_bitmap, output_bmp_buffer); - if (save_result.isError()) { // For Result, isError() or checking error() != E::Ok + if (save_result.isError()) { std::cerr << "BmpTool::save failed: " << static_cast(save_result.error()) << std::endl; return 1; } - std::cout << "BmpTool::Bitmap saved to buffer." << std::endl; - - // To get the actual size of the BMP written to the buffer (needed for writing to file): - // One way is to read bfSize from the header in output_bmp_buffer - // For example: - // #include "src/bitmapfile/bitmap_file.h" // For BITMAPFILEHEADER definition - // BITMAPFILEHEADER* fh = reinterpret_cast(output_bmp_buffer.data()); - // size_t actual_written_size = fh->bfSize; - // This requires including the BITMAPFILEHEADER definition. - // The save function itself doesn't return it, so this is a known aspect of the API. - // For this example, we'll use estimated_output_size, but actual_written_size is more robust. - // A more robust approach would be to parse bfSize or ensure save guarantees fitting within the span and updating its size. - // For this example, we assume the buffer is large enough and we write what's estimated. - // If the actual BMP is smaller, this might write extra uninitialized bytes from the buffer. - // If actual is larger (should not happen with correct estimation and save), it's a problem. - // The best is to parse bfSize from output_bmp_buffer.data(). - - if (write_buffer_to_file("output_new_api.bmp", output_bmp_buffer, estimated_output_size /* ideally actual_written_size from parsed header */)) { - std::cout << "Output buffer saved to output_new_api.bmp" << std::endl; + std::cout << "BmpTool::Bitmap saved to output buffer." << std::endl; + + // 6. Determine actual size of BMP written to buffer and write to file + // The BMP File Header (BITMAPFILEHEADER) is at the start of the buffer. + // Its bfSize field contains the total size of the BMP file. + BITMAPFILEHEADER* fh = reinterpret_cast(output_bmp_buffer.data()); + size_t actual_written_size = fh->bfSize; + + // Ensure actual_written_size is not greater than our buffer to prevent reading out of bounds. + if (actual_written_size > max_output_size) { + std::cerr << "Error: saved BMP size (" << actual_written_size + << ") exceeds buffer capacity (" << max_output_size << ")." << std::endl; + return 1; + } + + if (write_buffer_to_file(output_filename, output_bmp_buffer, actual_written_size)) { + std::cout << "Processed image saved to '" << output_filename << "'" << std::endl; } else { - std::cerr << "Failed to write output_new_api.bmp." << std::endl; + std::cerr << "Failed to write output to '" << output_filename << "'." << std::endl; + return 1; } return 0; @@ -146,56 +170,88 @@ int main() { ## Building the Project -The project uses CMake for building. +The project uses CMake for building. Ensure you have CMake (version 3.10 or newer) and a C++20 compatible compiler installed. ```bash -# Create a build directory +# Create a build directory (out-of-source build is recommended) mkdir build cd build -# Configure the project +# Configure the project (from the build directory) cmake .. -# Build the library (if configured as a library) and executables (like main example and tests) +# Build the library and executables (e.g., testexe, tests) +# On Linux/macOS with Makefiles (default) make -# or use your specific build system command e.g., mingw32-make +# On Windows with Visual Studio, after cmake .. you might open the .sln or use: +# cmake --build . --config Release +# For MinGW users: +# mingw32-make -# Run tests (if configured) +# Run tests (if configured and built) +# From the build directory ctest -# or directly run the test executable: ./bitmap_tests (or tests\bitmap_tests.exe on Windows) +# or directly run the test executable (e.g., ./tests/bitmap_tests or build\tests\Debug\bitmap_tests.exe) ``` -## Basic Usage Example +## Basic Usage Example (Old API) + +The following example demonstrates basic usage of the older, file-based API found in `src/bitmap/bitmap.h` and `src/bitmapfile/bitmap_file.h`. ```cpp -#include "bitmap/bitmap.h" // Adjust path if necessary, assumes src/ is an include dir +#include "bitmap/bitmap.h" // Old API (assumes src/ is an include directory or path adjusted) #include int main() { - Bitmap::File myBitmap; + Bitmap::File myBitmap; // Uses the old Bitmap::File class - // Load an image + // Load an image directly from a file path if (!myBitmap.Open("input.bmp")) { - std::cerr << "Error opening input.bmp" << std::endl; + std::cerr << "Error opening input.bmp using old API" << std::endl; return 1; } + std::cout << "Loaded input.bmp using old API." << std::endl; - // Apply some manipulations - myBitmap = GreyscaleImage(myBitmap); - myBitmap = ChangeImageBrightness(myBitmap, 1.2f); // Increase brightness by 20% - myBitmap = ApplyBoxBlur(myBitmap, 2); // Apply box blur with radius 2 + // Apply some manipulations (old API functions often return a new Bitmap::File) + Bitmap::File processedBitmap = GreyscaleImage(myBitmap); + processedBitmap = ChangeImageBrightness(processedBitmap, 1.2f); // Increase brightness by 20% + processedBitmap = ApplyBoxBlur(processedBitmap, 2); // Apply box blur with radius 2 + std::cout << "Applied manipulations using old API." << std::endl; - // Save the result - if (!myBitmap.SaveAs("output.bmp")) { - std::cerr << "Error saving output.bmp" << std::endl; + // Save the result to a new file path + if (!processedBitmap.SaveAs("output_old_api.bmp")) { + std::cerr << "Error saving output_old_api.bmp using old API" << std::endl; return 1; } - std::cout << "Image processed and saved as output.bmp" << std::endl; + std::cout << "Image processed and saved as output_old_api.bmp using old API" << std::endl; return 0; } ``` -Refer to `main.cpp` for more examples. +The `main.cpp` in the root of the repository demonstrates usage of the **new `BmpTool` API**. + +## Code Documentation + +The public API for `BmpTool` in `include/bitmap.hpp` is documented using Doxygen-style comments. + +If Doxygen is installed, you can generate the full HTML documentation by: +1. Installing Doxygen. +2. Creating a Doxyfile configuration (e.g., `doxygen -g Doxyfile` in the project root). +3. Customizing the `Doxyfile` (e.g., set `INPUT` to `include/`, `RECURSIVE` to `YES`). +4. Running `doxygen Doxyfile` from the project root. +The documentation will then be available in the specified output directory (e.g., `html/`). + +## Contributing + +Contributions to this project are welcome! Please follow these basic guidelines: + +1. **Fork the repository:** Create your own fork of the project on GitHub. +2. **Create a branch:** Make a new branch in your fork for your feature or bug fix (e.g., `feature/new-filter` or `fix/brightness-bug`). +3. **Make your changes:** Implement your changes, ensuring code is clear and follows existing style where possible. +4. **Add tests:** If you're adding a new feature or fixing a bug, please add appropriate unit tests in the `tests/` directory. Ensure all tests pass by running `ctest` or the test executable. +5. **Commit your changes:** Make clear, concise commit messages. +6. **Push to your fork:** Push your changes to your branch on your fork. +7. **Submit a Pull Request (PR):** Open a PR from your branch to the main repository's `main` branch. Provide a clear description of your changes in the PR. ## Fuzz Testing diff --git a/src/matrix/Documentation/Matrix.MD b/src/matrix/Documentation/Matrix.MD index d1222ff..f3d4662 100644 --- a/src/matrix/Documentation/Matrix.MD +++ b/src/matrix/Documentation/Matrix.MD @@ -11,10 +11,10 @@ The **Matrix** library provides a set of classes and iterators for creating and ## Classes Overview 1. **`MatrixRowIterator`**: An iterator for traversing elements within a matrix row. -2. **`MatrixColumnIterator`**: An iterator for traversing elements within a matrix column. -3. **`MatrixIterator`**: An iterator for traversing rows within a matrix. -4. **`MatrixRow`**: Represents a single row in a matrix. -5. **`Matrix`**: Represents a two-dimensional matrix composed of `MatrixRow` objects. +2. **`MatrixColumnIterator`**: An iterator for traversing elements within a matrix column (by stepping over `totalColumns` elements). +3. **`MatrixIterator`**: An iterator for traversing rows (`MatrixRow`) within a `Matrix`. +4. **`MatrixRow`**: Represents a single row in a matrix, managing its own data. +5. **`Matrix`**: Represents a two-dimensional matrix composed of `MatrixRow` objects, managing a collection of rows. --- @@ -28,7 +28,7 @@ A template class that provides a random-access iterator for iterating over the e #### Member Types -- `value_type`: Type of elements the iterator refers to (`typename MatrixRow::value_type`). +- `value_type`: Type of elements the iterator refers to (`typename MatrixRowType::value_type`). - `pointer`: Pointer to the element type (`value_type*`). - `reference`: Reference to the element type (`value_type&`). - `iterator_category`: Iterator category (`std::random_access_iterator_tag`). @@ -57,9 +57,8 @@ A template class that provides a random-access iterator for iterating over the e - `difference_type operator-(const MatrixRowIterator& other) const`: Calculates the difference between two iterators. - **Dereference Operators** - - `reference operator*()`: Dereferences the iterator to access the element. - - `const reference operator*() const`: Const version. - - `pointer operator->() const`: Accesses members of the element. + - `reference operator*()`: Dereferences the iterator to access the element (non-const). + - `pointer operator->() const`: Accesses members of the element. (Note: `m_ptr` itself is returned, allowing modification if `value_type` is not const). - `reference operator[](difference_type n) const`: Accesses the element at an offset `n` from the current position. - **Comparison Operators** @@ -69,6 +68,7 @@ A template class that provides a random-access iterator for iterating over the e - `bool operator<=(const MatrixRowIterator& other) const`: Less-than-or-equal comparison. - `bool operator>(const MatrixRowIterator& other) const`: Greater-than comparison. - `bool operator>=(const MatrixRowIterator& other) const`: Greater-than-or-equal comparison. +(Note: The `MatrixRow` class provides `begin() const` and `end() const` which return `MatrixRowIterator`. If `MatrixRowIterator` is used with a const `MatrixRow`, `operator*` would effectively yield a const reference due to const propagation from `m_Data.get()`). --- @@ -131,9 +131,12 @@ A template class that provides an iterator for iterating over the rows of a matr #### Member Types -- `value_type`: Type of elements (rows) the iterator refers to (`typename Matrix::value_type`). +- `value_type`: Type of elements (rows) the iterator refers to (`typename MatrixType::value_type`, which is `MatrixRow`). - `pointer`: Pointer to the element type (`value_type*`). - `reference`: Reference to the element type (`value_type&`). +- `iterator_category`: Typically `std::random_access_iterator_tag` if full support is implemented, otherwise `std::input_iterator_tag` or `std::forward_iterator_tag`. (Header does not specify, but operations imply random access). +- `difference_type`: Type to express the difference between two iterators (`std::ptrdiff_t`). + #### Member Functions @@ -153,8 +156,9 @@ A template class that provides an iterator for iterating over the rows of a matr - `pointer operator->()`: Accesses members of the row. - **Comparison Operators** - - `bool operator==(MatrixIterator other)`: Equality comparison. - - `bool operator!=(MatrixIterator other)`: Inequality comparison. + - `bool operator==(const MatrixIterator& other) const`: Equality comparison. + - `bool operator!=(const MatrixIterator& other) const`: Inequality comparison. + (Note: `<, <=, >, >=` operators are not explicitly defined in the header for `MatrixIterator`.) --- @@ -171,30 +175,41 @@ A template class representing a single row in a matrix. It manages a dynamic arr #### Constructors -- `MatrixRow()`: Default constructor. -- `explicit MatrixRow(size_t size)`: Constructs a `MatrixRow` with the specified size. +- `MatrixRow()`: Default constructor. Initializes an empty row with size and capacity 0. +- `explicit MatrixRow(size_t size)`: Constructs a `MatrixRow` with the specified `size`. Elements are default initialized (e.g., to 0 for numeric types). +- `MatrixRow(const MatrixRow& other)`: Copy constructor. Performs a deep copy of the other row's elements. +- `MatrixRow(MatrixRow&& other) noexcept`: Move constructor. Takes ownership of the other row's data. + +#### Assignment Operators +- `MatrixRow& operator=(const MatrixRow& other)`: Copy assignment operator. Performs a deep copy. +- `MatrixRow& operator=(MatrixRow&& other) noexcept`: Move assignment operator. Takes ownership of the other row's data. + +#### Destructor +- `~MatrixRow()`: Defaulted destructor, handles memory deallocation via `std::unique_ptr`. + #### Member Functions - **Resizing and Assignment** - - `void resize(size_t newSize)`: Resizes the row to `newSize`. - - `void assign(size_t size, T val)`: Assigns the value `val` to all elements, resizing the row to `size`. - - `void assign(T val)`: Assigns the value `val` to all existing elements. + - `void resize(size_t newSize)`: Resizes the row to `newSize`. If `newSize` is smaller, elements are truncated. If larger, new elements are default initialized. + - `void assign(size_t size, T val)`: Resizes the row to `size` and assigns the value `val` to all elements. + - `void assign(T val)`: Assigns the value `val` to all existing elements without changing the size. - **Accessors** - `size_t size() const`: Returns the number of elements in the row. - - `size_t capacity()`: Returns the capacity of the row. - - `T at(size_t i) const`: Returns the element at index `i`, with bounds checking. + - `size_t capacity() const`: Returns the current capacity of the row (typically same as size in this implementation). + - `T at(size_t i) const`: Returns the element at index `i`, with bounds checking (throws `std::out_of_range` if `i` is invalid). + - `T& at(size_t i)`: Returns a reference to the element at index `i`, with bounds checking. - **Operators** - - `T& operator[](size_t i)`: Accesses the element at index `i` with bounds checking. - - `const T& operator[](size_t i) const`: Const version. + - `T& operator[](size_t i)`: Accesses the element at index `i`. **No bounds checking is performed.** + - `const T& operator[](size_t i) const`: Const version. **No bounds checking is performed.** - **Iterators** - `Iterator begin()`: Returns an iterator to the beginning of the row. - `Iterator end()`: Returns an iterator to the end of the row. - - `Iterator begin() const`: Const version. - - `Iterator end() const`: Const version. + - `Iterator begin() const`: Const version, returns an iterator to the beginning of a const row. + - `Iterator end() const`: Const version, returns an iterator to the end of a const row. --- @@ -208,67 +223,81 @@ A template class representing a two-dimensional matrix composed of `MatrixRow - `value_type`: Type of rows stored in the matrix (`MatrixRow`). - `Iterator`: An iterator type (`MatrixIterator>`) for iterating over matrix rows. -- `ColumnIterator`: An iterator type (`MatrixColumnIterator`) for iterating over matrix columns. +- `ColumnIterator`: An iterator type (`MatrixColumnIterator`) for iterating over elements in a specific column (conceptual, not directly provided as `begin_col`/`end_col` by `Matrix` class itself). #### Constructors -- `Matrix()`: Default constructor. -- `explicit Matrix(int row_count, int column_count)`: Constructs a matrix with the specified number of rows and columns. +- `Matrix()`: Default constructor. Initializes an empty matrix (0 rows, 0 columns). +- `explicit Matrix(size_t row_count, size_t column_count)`: Constructs a matrix with the specified number of rows and columns. Elements are default initialized. +- `Matrix(size_t row_count, size_t column_count, const T& initial_value)`: Constructs a matrix and initializes all elements to `initial_value`. +- `Matrix(const Matrix& other)`: Copy constructor. Performs a deep copy. +- `Matrix(Matrix&& other) noexcept`: Move constructor. Takes ownership of `other`'s data. + +#### Assignment Operators +- `Matrix& operator=(const Matrix& other)`: Copy assignment operator. Performs a deep copy. +- `Matrix& operator=(Matrix&& other) noexcept`: Move assignment operator. Takes ownership of `other`'s data. + +#### Destructor +- `~Matrix()`: Defaulted destructor, handles memory deallocation via `std::unique_ptr`. #### Member Functions - **Accessors** - - `size_t size() const`: Returns the total number of elements in the matrix. + - `size_t size() const`: Returns the total number of elements in the matrix (rows * columns). - `size_t rows() const`: Returns the number of rows. - `size_t cols() const`: Returns the number of columns. - - `size_t capacity() const`: Returns the capacity of the matrix. + - `size_t capacity() const`: Returns the capacity of the matrix in terms of the number of rows it can store without reallocation of the main row array. + - `bool empty() const`: Returns `true` if the matrix has 0 rows or 0 columns, `false` otherwise. + - `T at(size_t r, size_t c) const`: Returns the element at row `r` and column `c`, with bounds checking. + - `T& at(size_t r, size_t c)`: Returns a reference to the element at row `r` and column `c`, with bounds checking. - **Resizing and Assignment** - - `void resize(size_t row_count, size_t col_count)`: Resizes the matrix to the specified dimensions. - - `void assign(size_t row_count, size_t col_count, const T val)`: Resizes and assigns `val` to all elements. - - `void assign(const T val)`: Assigns `val` to all existing elements. + - `void resize(size_t row_count, size_t col_count)`: Resizes the matrix. Existing elements that fit are preserved. New elements are default initialized. + - `void resize(size_t row_count, size_t col_count, const T& val)`: Resizes the matrix. Existing elements that fit are preserved. New elements are initialized to `val`. Other elements are assigned `val`. + - `void assign(size_t row_count, size_t col_count, const T& val)`: Resizes the matrix and assigns `val` to all its elements. + - `void assign(const T& val)`: Assigns `val` to all existing elements without changing dimensions. - **Matrix Manipulation** - - `Matrix MergeVertical(const Matrix& b) const`: Merges the current matrix with another matrix `b` vertically. - - `Matrix MergeHorizontal(const Matrix& b) const`: Merges the current matrix with another matrix `b` horizontally. - - `std::vector> SplitVertical() const`: Splits the matrix vertically into two equal parts. - - `std::vector> SplitVertical(size_t num) const`: Splits the matrix vertically into `num` equal parts. - - `std::vector> SplitHorizontal() const`: Splits the matrix horizontally into two equal parts. - - `std::vector> SplitHorizontal(size_t num) const`: Splits the matrix horizontally into `num` equal parts. - - `Matrix SigmoidMatrix()`: Applies the sigmoid function to each element of the matrix. - - `Matrix Randomize()`: Randomizes the elements of the matrix with values between -1.0 and 1.0. - - `Matrix CreateIdentityMatrix()`: Converts the matrix into an identity matrix (must be square). - - `Matrix ZeroMatrix() const`: Sets all elements to zero. + - `Matrix MergeVertical(const Matrix& b) const`: Merges the current matrix with matrix `b` vertically (appends rows of `b`). Matrices must have the same number of columns, unless one is empty. + - `Matrix MergeHorizontal(const Matrix& b) const`: Merges the current matrix with matrix `b` horizontally (appends columns of `b`). Matrices must have the same number of rows, unless one is empty. + - `std::vector> SplitVertical(size_t num_splits = 2) const`: Splits the matrix vertically into `num_splits` parts. Number of rows must be divisible by `num_splits`. + - `std::vector> SplitHorizontal(size_t num_splits = 2) const`: Splits the matrix horizontally into `num_splits` parts. Number of columns must be divisible by `num_splits`. + - `Matrix& SigmoidMatrix()`: Applies the sigmoid function `1 / (1 + exp(-x))` to each element of the matrix, modifying it in-place. Returns `*this`. + - `Matrix& Randomize()`: Randomizes the elements of the matrix with values typically between -1.0 and 1.0 (uses `std::uniform_real_distribution`). Modifies in-place. Returns `*this`. + - `Matrix& CreateIdentityMatrix()`: Converts the matrix into an identity matrix (must be square). Modifies in-place. Returns `*this`. + - `Matrix& ZeroMatrix()`: Sets all elements to zero. Modifies in-place. Returns `*this`. - `Matrix Transpose() const`: Returns the transpose of the matrix. - - `T Determinant() const`: Returns the determinant of the matrix. - - `Matrix Inverse()`: Returns the inverse of the matrix. + - `T Determinant() const`: Returns the determinant of the matrix (must be square). Uses Laplace expansion (recursive). + - `Matrix Inverse() const`: Returns the inverse of the matrix (must be square and non-singular). - **Operators** - - `MatrixRow& operator[](size_t i)`: Accesses the row at index `i`. - - `const MatrixRow& operator[](size_t i) const`: Const version. + - `MatrixRow& operator[](size_t i)`: Accesses the row at index `i`. **No bounds checking.** + - `const MatrixRow& operator[](size_t i) const`: Const version. **No bounds checking.** - **Arithmetic Operators** - **Addition** - - `Matrix operator+(const Matrix& b)`: Adds two matrices element-wise. - - `Matrix operator+(const T b) const`: Adds a scalar to each element. - - `Matrix operator+=(const Matrix& b) const`: Adds another matrix to this matrix. - - `Matrix operator+=(const T b) const`: Adds a scalar to each element. + - `Matrix operator+(const Matrix& b) const`: Adds two matrices element-wise. + - `Matrix operator+(const T& b) const`: Adds a scalar `b` to each element. + - `Matrix& operator+=(const Matrix& b)`: Adds another matrix to this matrix (in-place). + - `Matrix& operator+=(const T& b)`: Adds a scalar `b` to each element (in-place). - **Subtraction** - `Matrix operator-(const Matrix& b) const`: Subtracts another matrix from this matrix element-wise. - - `Matrix operator-(const T b) const`: Subtracts a scalar from each element. - - `Matrix operator-=(const Matrix& b) const`: Subtracts another matrix from this matrix. - - `Matrix operator-=(const T b) const`: Subtracts a scalar from each element. + - `Matrix operator-(const T& b) const`: Subtracts a scalar `b` from each element. + - `Matrix& operator-=(const Matrix& b)`: Subtracts another matrix from this matrix (in-place). + - `Matrix& operator-=(const T& b)`: Subtracts a scalar `b` from each element (in-place). - **Multiplication** - - `Matrix operator*(const Matrix& b) const`: Multiplies two matrices (matrix multiplication). - - `Matrix operator*(const T b) const`: Multiplies each element by a scalar. - - `Matrix operator*=(const T b) const`: Multiplies each element by a scalar. + - `Matrix operator*(const Matrix& b) const`: Multiplies two matrices (matrix multiplication). Requires `this->cols() == b.rows()`. + - `Matrix operator*(const T& b) const`: Multiplies each element by a scalar `b`. + - `Matrix& operator*=(const T& b)`: Multiplies each element by a scalar `b` (in-place). - **Division** - - `Matrix operator/(const T b) const`: Divides each element by a scalar. - - `Matrix operator/=(const T b) const`: Divides each element by a scalar. + - `Matrix operator/(const T& b) const`: Divides each element by a scalar `b`. Throws `std::runtime_error` for division by zero. + - `Matrix& operator/=(const T& b)`: Divides each element by a scalar `b` (in-place). Throws `std::runtime_error` for division by zero. - **Iterators** - - `Iterator begin()`: Returns an iterator to the beginning of the matrix (rows). - - `Iterator end()`: Returns an iterator to the end of the matrix. + - `Iterator begin()`: Returns an iterator to the beginning of the matrix (first row). + - `Iterator end()`: Returns an iterator to the end of the matrix (one past the last row). + - `Iterator begin() const`: Const version. + - `Iterator end() const`: Const version. --- @@ -280,13 +309,14 @@ A template class representing a two-dimensional matrix composed of `MatrixRow #include "Matrix.h" int main() { - // Create a 3x3 matrix of integers + // Create a 3x3 matrix of integers, initialized to default (0 for int) Matrix::Matrix mat(3, 3); // Assign values to the matrix - mat.assign(1); // Set all elements to 1 + mat.assign(1); // Set all elements to 1 using assign - // Modify specific elements + // Modify specific elements using operator[] (no bounds check) + // For bounds-checked access, use mat.at(row, col) = value; mat[0][0] = 5; mat[1][1] = 10; mat[2][2] = 15; @@ -334,13 +364,15 @@ int main() { Matrix::Matrix mat2(3, 2); // Initialize matrices with random values + // Initialize matrices (Randomize modifies in-place and returns a reference) mat1.Randomize(); mat2.Randomize(); // Multiply matrices - Matrix::Matrix result = mat1 * mat2; + Matrix::Matrix result = mat1 * mat2; // mat1.operator*(mat2) // Output the result + // Using operator[] (no bounds check). For bounds-checked access, use result.at(i,j) for (size_t i = 0; i < result.rows(); ++i) { for (size_t j = 0; j < result.cols(); ++j) { std::cout << result[i][j] << " "; @@ -353,21 +385,31 @@ int main() { ``` ## Notes - - Type Requirements: The Matrix class assumes that the type T supports basic arithmetic operations such as addition, subtraction, multiplication, and division. - - Exception Handling: Exception handling is implemented for index bounds checking and invalid operations (e.g., merging matrices with incompatible dimensions). - - Modern C++ Features: The code uses modern C++ features such as smart pointers (std::unique_ptr), templates, and the Standard Template Library (STL). + - Type Requirements: The Matrix class assumes that the type `T` supports basic arithmetic operations (e.g., `+`, `-`, `*`, `/`), copy/move construction/assignment, and default construction. For functions like `Determinant`, `Inverse`, `SigmoidMatrix`, specific properties (e.g., being a numeric type) are implicitly required. + - Exception Handling: Exception handling is implemented for index bounds checking in `at()` methods, invalid operations (e.g., merging matrices with incompatible dimensions, determinant of non-square matrix, division by zero), and memory allocation failures (implicitly via `std::unique_ptr`). + - Modern C++ Features: The code uses modern C++ features such as smart pointers (`std::unique_ptr`), templates, move semantics (constructors and assignment operators), and the Standard Template Library (STL) (e.g., `std::vector`, `std::algorithm`, `std::iterator`). + - Performance: `operator[]` for `MatrixRow` and `Matrix` do not perform bounds checking for performance reasons, similar to `std::vector::operator[]`. Use the `at()` methods for safe, bounds-checked access. ## Conclusion -The Matrix library provides a flexible and efficient way to work with matrices in C++. With support for various matrix operations and custom iterators, it can be integrated into applications that require matrix computations, such as scientific computing, graphics, and machine learning. +The Matrix library provides a flexible and efficient way to work with matrices in C++. With support for various matrix operations, custom iterators, and modern C++ memory management, it can be integrated into applications that require matrix computations, such as scientific computing, graphics, and machine learning. ## Potential Improvements -- Error Handling: Enhance exception messages for more clarity. -- Optimizations: Implement move semantics where applicable for performance improvements. -- Additional Functions: Add more mathematical operations like determinant calculation, inverse, eigenvalues, etc. -- Template Specializations: Provide specializations for common types (e.g., int, float, double) for optimized performance. +- **Error Handling**: Enhance exception messages for even more clarity and context. +- **Performance Optimizations**: + - Explore expression templates to reduce temporary object creation in chained operations. + - For performance-critical applications, investigate SIMD optimizations for arithmetic operations. +- **Additional Functions**: + - Eigenvalue and eigenvector calculations. + - Decompositions like QR, SVD. + - More specialized matrix types (e.g., SparseMatrix, SymmetricMatrix). +- **Template Specializations**: Provide explicit specializations for common types (e.g., `float`, `double`) if specific optimized algorithms for those types are beneficial. +- **Iterator Enhancements**: + - Ensure all iterators fully conform to `std::random_access_iterator_tag` requirements if not already the case (e.g., `MatrixIterator` comparison operators). + - Consider adding `const_iterator` types explicitly for `MatrixRow` and `Matrix` for more C++ idiomatic const-correctness, although `begin() const` returning a non-const iterator type that operates on const data is a common pattern. +- **Concurrency**: Add support for parallelized operations for large matrices. ## References -- C++ Standard Library: Utilizes features from the C++ Standard Library, including iterators and smart pointers. -- Iterator Requirements: Conforms to the C++ iterator requirements for compatibility with STL algorithms. +- C++ Standard Library: Utilizes features from the C++ Standard Library, including iterators, smart pointers, algorithms, and exception classes. +- Iterator Requirements: Aims to conform to C++ iterator requirements for compatibility with STL algorithms.