Welcome to MatrixBandwidth.jl! Thank you for your interest in contributing to this package. Kindly peruse these guidelines before opening an issue or submitting a pull request (PR).
Most issues are either bug reports or feature requests; we describe the expectations for each type below. If your issue does not fit into either category, feel free to open it anyway—just be clear, concise, and of course respectful!
If you encounter a bug, please include a minimal reproducible example containing the code necessary to reproduce the bug, along with the expected and actual behavior. Additionally, please provide information about your operating system, Julia version, and MatrixBandwidth.jl version. (If you are unsure about how to find this information, feel free to reach out anyway, and we can guide you through the process.)
When suggesting a new feature, please provide a clear and concise description of your idea, along with concrete motivation for its inclusion in the package. If applicable, include references to relevant literature or existing implementations in other software. And of course, if you wish to implement the feature yourself, please indicate so in your issue, and we can get you underway to submitting a PR!
Before writing a PR, we would prefer if you first reached out via an issue to check whether your contribution would fit well with the repository. Once in the process of actually writing a PR, please adhere to the following guidelines:
When introducing new features to the package, unit tests are of paramount importance to ensure that your code behaves as expected. Please add them to the test/ directory, following the existing structure and conventions: a unit test meant for a method in src/<path>/<file>.jl should be placed in test/<path>/<file>.jl.
Equally crucial is proper documentation. Judicious use of inline comments in complex sections is encouraged to enhance code readability, regardless of whether the method/struct is public or private. For public methods/structs, please also include docstrings matching the style of existing documentation. At bare minimum, methods should have a one-liner summary of their purpose along with descriptions of all arguments and return values, and structs should have a one-liner summary of their purpose along with descriptions of all fields. Less trivial methods/structs should have more extensive documentation—examples in particular are highly recommended.
Moreover, we maintain a changelog documenting all the nontrivial changes made to this repository with each new release. After submitting a PR and obtaining the corresponding PR number from GitHub, please add a note referencing this number to the changelog and push the update to your branch. This note should go under the Added, Changed, Fixed, or Removed subsection (as appropriate) of the Unreleased section. For instance, the creation of this file was logged under the Added subsection with the entry - Added a CONTRIBUTING.md file with contributing guidelines (#183).
Format your code with JuliaFormatter in the package's environment before pushing; our .JuliaFormatter.toml file will automatically enforce Invenia's BlueStyle, with a few modifications.
While not always necessary, strive to write efficient code, especially for performance-critical sections. Moreover, try to avoid adding unnecessary dependencies to the package; if you absolutely must, please justify its inclusion in your PR description.
One of the most valued ways to contribute is by adding a new matrix bandwidth reduction algorithm to the interface (although bug fixes, documentation improvements, and other feature additions are always welcome). Of course, not all algorithms are suitable for inclusion, so it is best to first open an issue to discuss the possibility. While doing so, be sure to specify to which category your algorithm belongs—minimization (exact, heuristic, or metaheuristic) or recognition—and provide reference(s) to the original publication(s) describing the algorithm.
If your proposal is approved and you are implementing a bandwidth minimization algorithm, navigate to the appropriate directory (src/Minimization/Exact/, src/Minimization/Heuristic/, or src/Minimization/Metaheuristic/) and follow these steps:
- Create a new file in the
solvers/subdirectory named after your algorithm (e.g.,cuthill_mckee.jlfor the Cuthill–McKee and reverse Cuthill–McKee algorithms). - Define a new subtype of
ExactSolver,HeuristicSolver, orMetaheuristicSolver(as appropriate) to represent your algorithm. For instance, the reverse Cuthill–McKee algorithm uses theReverseCuthillMcKeestruct insolvers/cuthill_mckee.jl. - Add the algorithm to the appropriate entry of the
MatrixBandwidth.ALGORITHMSconstant, like so:push!(MatrixBandwidth.ALGORITHMS[:Minimization][:Heuristic], ReverseCuthillMcKee). - Overload
Base.summaryto return the name of your algorithm andMatrixBandwidth._requires_structural_symmetryto indicate whether your algorithm requires a structurally symmetric matrix. For example:Base.summary(::ReverseCuthillMcKee) = "Reverse Cuthill–McKee"andMatrixBandwidth._requires_structural_symmetry(::ReverseCuthillMcKee) = true. - Implement a corresponding
Minimization._minimize_bandwidth_impl(::AbstractMatrix{Bool}, ::NewSolverType)method with the core algorithm logic. Do not attempt to directly overload theminimize_bandwidthfunction, as this contains common preprocessing, postprocessing, and input validation logic shared by all minimization algorithms. - Export your new solver struct from both
src/Minimization/Minimization.jland the appropriate submodule file (eitherMinimization/Exact/Exact.jl,Minimization/Heuristic/Heuristic.jl, orMinimization/Metaheuristic/Metaheuristic.jl). - Properly document your solver struct and add unit tests in the corresponding test file, adhering to the guidelines outlined above.
For a good reference implementation, you may look at src/Minimization/Heuristic/solvers/cuthill_mckee.jl and its associated test suite in test/Minimization/Heuristic/solvers/cuthill_mckee.jl. Also refer to src/Minimization/Minimization.jl and src/Minimization/Heuristic/Heuristic.jl for guidance on exporting your new solver struct.
The process for adding a bandwidth recognition algorithm, once your proposal is approved, is very similar. First, navigate to the src/Recognition/ directory, then follow these steps:
- Create a new file in the
deciders/subdirectory named after your algorithm (e.g.,del_corso_manzini.jlfor the Del Corso–Manzini and Del Corso–Manzini with perimeter search algorithms). - Define a new subtype of
AbstractDeciderto represent your algorithm. For instance, the Del Corso–Manzini algorithm uses theDelCorsoManzinistruct indeciders/del_corso_manzini.jl. - Add the algorithm to the
MatrixBandwidth.ALGORITHMS[:Recognition]constant, like so:push!(MatrixBandwidth.ALGORITHMS[:Recognition], DelCorsoManzini). - Overload
Base.summaryto return the name of your algorithm andMatrixBandwidth._requires_structural_symmetryto indicate whether your algorithm requires a structurally symmetric matrix. For example:Base.summary(::DelCorsoManzini) = "Del Corso–Manzini"andMatrixBandwidth._requires_structural_symmetry(::DelCorsoManzini) = true. - Implement a corresponding
Recognition._has_bandwidth_k_ordering_impl(::AbstractMatrix{Bool}, ::Integer, ::NewDeciderType)method with the core algorithm logic. Do not attempt to directly overload thehas_bandwidth_k_orderingfunction, as this contains common preprocessing, postprocessing, and input validation logic shared by all recognition algorithms. - Export your new decider struct from
src/Recognition/Recognition.jl. - Properly document your decider struct and add unit tests in the corresponding test file, adhering to the guidelines outlined above.
For a good reference implementation, you may look at src/Recognition/deciders/del_corso_manzini.jl and its associated test suite in test/Recognition/deciders/del_corso_manzini.jl. Also refer to src/Recognition/Recognition.jl for guidance on exporting your new decider struct.
When adding substantial new features, it is important to cite relevant literature in the documentation. Add a # References section in the docstring of the relevant method/struct, and include citations in BibTeX format in docs/src/refs.bib. For example, the profile function in src/core.jl includes the citation
"""
# References
- [Maf14](@cite): L. O. Mafteiu-Scai. *The Bandwidths of a Matrix. A Survey of Algorithms*.
Annals of West University of Timisoara - Mathematics and Computer Science **52**,
183–223 (2014). https://doi.org/10.2478/awutm-2014-0019.
"""with corresponding BibTeX entry
@article{Maf14,
author = {Mafteiu-Scai, Liviu Octavian},
journal = {Annals of West University of Timisoara - Mathematics and Computer Science},
number = {2},
title = {The Bandwidths of a Matrix. A Survey of Algorithms},
volume = {52},
year = {2014},
pages = {183--223},
url = {https://doi.org/10.2478/awutm-2014-0019}
}