diff --git a/README.md b/README.md index ca0315f0f..5c2c51f97 100644 --- a/README.md +++ b/README.md @@ -75,13 +75,20 @@ To build `qsyn`, follow the instructions below:
For Linux Users - -You'll probably need to install `OpenBLAS` and `LAPACK` libraries. For Ubuntu, you can install them by running -```sh -sudo apt install libopenblas-dev -sudo apt install liblapack-dev -``` +You'll probably need to install `OpenBLAS` and `LAPACK` libraries. +- For Ubuntu, you can install them by running + ```sh + sudo apt install libopenblas-dev + sudo apt install liblapack-dev + ``` +- For Fedora, you can install them by running + ```sh + sudo dnf install openblas-devel + sudo dnf install lapack-devel + ``` +- For openSUSE, you can read [this wiki page](https://en.opensuse.org/openSUSE:Science_Linear_algebra_libraries). +- For other distros, you might be interested in [OpenBLAS install.md](https://github.com/OpenMathLib/OpenBLAS/blob/develop/docs/install.md). If you are tech-savvy enough to be using a different Linux distribution, we're confident that you can figure out how to install these libraries 😉 @@ -97,7 +104,7 @@ This uses the default compiler (gcc/g++) and triggers the CMake build. To overri
For MacOS Users - + Since Qsyn uses C++20 features not fully supported by Apple Clang, install a C++20-capable compiler. Options: 1. **LLVM (clang++)** via Homebrew: @@ -332,26 +339,26 @@ This architecture is central to qsyn’s flexibility and extensibility. It segre ### Data Access and Utilities `qsyn` provides various data representations for quantum logic. `
` stands for any data representation type, including quantum circuits, ZX diagrams, Tableau, etc. -| Command | Description | -| :----- | :---- | -| `
` list | list all `
`s | -| `
` checkout | switch focus between `
`s | - | `
` print | print `
` information | -| `
` | add a new/delete a `
` | -| `
` | read and write `
` | -| `
` equiv | verify equivalence of two `
`s | -| `
` draw | render visualization of `
` | -| convert `` `` | convert from `` to `` | +| Command | Description | +| :---------------------- | :-------------------------------- | +| `
` list | list all `
`s | +| `
` checkout | switch focus between `
`s | +| `
` print | print `
` information | +| `
` | add a new/delete a `
` | +| `
` | read and write `
` | +| `
` equiv | verify equivalence of two `
`s | +| `
` draw | render visualization of `
` | +| convert `` `` | convert from `` to `` | There are also some extra utilities: -| Command | Description | -| :----- | :---- | -| alias | set or unset aliases | -| help | display helps to commands | +| Command | Description | +| :------ | :----------------------------- | +| alias | set or unset aliases | +| help | display helps to commands | | history | show or export command history | -| logger | control log levels | -| set | set or unset variables | -| usage | show time/memory usage | +| logger | control log levels | +| set | set or unset variables | +| usage | show time/memory usage | ## License @@ -363,7 +370,7 @@ Certain functions of `qsyn` is enabled by a series of third-party libraries. For ## Resources * Quantum circuit benchmark: [qsyn-benchmark](https://github.com/DVLab-NTU/qsyn-benchmark) - + ## Reference If you are using Qsyn for your research, it will be greatly appreciated if you cite this publication: diff --git a/src/argparse/arg_parser.cpp b/src/argparse/arg_parser.cpp index de09d4abb..4bae59e9b 100644 --- a/src/argparse/arg_parser.cpp +++ b/src/argparse/arg_parser.cpp @@ -52,6 +52,7 @@ bool SubParsers::is_required() const noexcept { return _pimpl->required; } +SubParsers::MapType& SubParsers::get_subparsers() { return _pimpl->subparsers; } SubParsers::MapType const& SubParsers::get_subparsers() const { return _pimpl->subparsers; } std::string const& SubParsers::get_help() const { return _pimpl->help; } std::string const& SubParsers::get_dest() const { return _pimpl->dest; } @@ -487,8 +488,9 @@ bool ArgumentParser::_parse_positional_arguments(TokensSpan tokens, std::vector< fmt::println(stderr, "Error: missing argument \"{}\": expected {}{} arguments!!", arg.get_name(), (lower < upper ? "at least " : ""), lower); return false; - } else + } else { continue; + } } if (!arg.take_action(parse_range)) return false; diff --git a/src/argparse/arg_parser.hpp b/src/argparse/arg_parser.hpp index b71fb154c..b21560ecf 100644 --- a/src/argparse/arg_parser.hpp +++ b/src/argparse/arg_parser.hpp @@ -49,6 +49,7 @@ class SubParsers { size_t size() const noexcept; + SubParsers::MapType& get_subparsers(); SubParsers::MapType const& get_subparsers() const; std::string const& get_help() const; std::string const& get_dest() const; diff --git a/src/cmd/conversion_cmd.cpp b/src/cmd/conversion_cmd.cpp index 6cc85bd36..2d5cbb789 100644 --- a/src/cmd/conversion_cmd.cpp +++ b/src/cmd/conversion_cmd.cpp @@ -159,8 +159,9 @@ Command convert_from_zx_cmd(zx::ZXGraphMgr& zxgraph_mgr, QCirMgr& qcir_mgr, tens zxgraph_mgr.add(zxgraph_mgr.get_next_id(), std::make_unique(std::move(target))); zxgraph_mgr.get()->add_procedure("ZX2QC-Unpermuted"); qcir_mgr.get()->add_procedure("ZX2QC-Unpermuted"); - } else + } else { qcir_mgr.get()->add_procedure("ZX2QC"); + } assert(std::ranges::all_of(qcir_mgr.get()->get_gates(), [&](auto* gate) { return gate->get_id() == qcir_mgr.get()->get_gate(gate->get_id())->get_id(); })); } diff --git a/src/cmd/qcir_cmd.cpp b/src/cmd/qcir_cmd.cpp index f6adedfc0..4b5ba4818 100644 --- a/src/cmd/qcir_cmd.cpp +++ b/src/cmd/qcir_cmd.cpp @@ -322,13 +322,13 @@ dvlab::Command qcir_print_cmd(QCirMgr const& qcir_mgr) { if (parser.parsed("--gate")) { auto gate_ids = parser.get>("--gate"); qcir_mgr.get()->print_gates(parser.parsed("--verbose"), gate_ids); - } else if (parser.parsed("--diagram")) + } else if (parser.parsed("--diagram")) { if (parser.parsed("--verbose")) { qcir_mgr.get()->draw(QCirDrawerType::text); } else { qcir_mgr.get()->print_circuit_diagram(); } - else if (parser.parsed("--statistics")) { + } else if (parser.parsed("--statistics")) { qcir_mgr.get()->print_qcir(); qcir_mgr.get()->print_gate_statistics(parser.parsed("--verbose")); fmt::println("Depth : {}", qcir_mgr.get()->calculate_depth()); diff --git a/src/device/device.cpp b/src/device/device.cpp index 2acbf28c5..cf56a3fa2 100644 --- a/src/device/device.cpp +++ b/src/device/device.cpp @@ -735,9 +735,9 @@ void Device::print_path(QubitIdType src, QubitIdType dest) const { } } std::vector const& path = get_path(src, dest); - if (path.front().get_id() != src && path.back().get_id() != dest) + if (path.front().get_id() != src && path.back().get_id() != dest) { fmt::println("No path between {} and {}", src, dest); - else { + } else { fmt::println("Path from {} to {}:", src, dest); size_t cnt = 0; for (auto& v : path) { diff --git a/src/duostra/mapping_eqv_checker.cpp b/src/duostra/mapping_eqv_checker.cpp index 007ce2e03..152c94a73 100644 --- a/src/duostra/mapping_eqv_checker.cpp +++ b/src/duostra/mapping_eqv_checker.cpp @@ -33,8 +33,9 @@ MappingEquivalenceChecker::MappingEquivalenceChecker(QCir* phy, QCir* log, Devic if (init.empty()) { auto placer = get_placer(placer_type); init = placer->place_and_assign(_device); - } else + } else { _device.place(init); + } for (auto const& [i, qubit] : tl::views::enumerate(_logical->get_qubits())) { _dependency[i] = _reverse ? qubit.get_last_gate() : qubit.get_first_gate(); } @@ -63,8 +64,9 @@ bool MappingEquivalenceChecker::check() { } } else if (phys_gate->get_num_qubits() > 1) { return false; - } else if (!execute_single(phys_gate)) + } else if (!execute_single(phys_gate)) { return false; + } } // REVIEW - check remaining gates in logical are swaps check_remaining(); diff --git a/src/duostra/placer.cpp b/src/duostra/placer.cpp index 2114977bf..8a4fa1352 100644 --- a/src/duostra/placer.cpp +++ b/src/duostra/placer.cpp @@ -59,6 +59,7 @@ std::vector BasePlacer::place_and_assign(Device& device) { */ std::vector RandomPlacer::_place(Device& device) const { std::vector assign; + assign.reserve(device.get_num_qubits()); for (size_t i = 0; i < device.get_num_qubits(); ++i) assign.emplace_back(i); @@ -76,6 +77,7 @@ std::vector RandomPlacer::_place(Device& device) const { */ std::vector StaticPlacer::_place(Device& device) const { std::vector assign; + assign.reserve(device.get_num_qubits()); for (size_t i = 0; i < device.get_num_qubits(); ++i) assign.emplace_back(i); diff --git a/src/qcir/oracle/pebble.cpp b/src/qcir/oracle/pebble.cpp index c415475b1..15f5c379e 100644 --- a/src/qcir/oracle/pebble.cpp +++ b/src/qcir/oracle/pebble.cpp @@ -79,7 +79,7 @@ std::optional from_xag_cuts(XAG const& xag, std::map optimal_cone_tips = optimal_cut | - views::filter([&is_input](auto const entry) { return !is_input(entry.first); }) | + views::filter([&is_input](auto const& entry) { return !is_input(entry.first); }) | views::keys | tl::to(); diff --git a/src/qcir/qcir_reader.cpp b/src/qcir/qcir_reader.cpp index 5d1dc296a..9ba633de6 100644 --- a/src/qcir/qcir_reader.cpp +++ b/src/qcir/qcir_reader.cpp @@ -29,11 +29,11 @@ namespace qsyn::qcir { std::optional from_file(std::filesystem::path const& filepath) { auto const extension = filepath.extension(); - if (extension == ".qasm") + if (extension == ".qasm") { return qcir::from_qasm(filepath); - else if (extension == ".qc") + } else if (extension == ".qc") { return qcir::from_qc(filepath); - else { + } else { spdlog::error("File format \"{}\" is not supported!!", extension); return std::nullopt; } @@ -159,9 +159,9 @@ std::optional from_qc(std::filesystem::path const& filepath) { n_qubit++; } } - } else if (line.find('#') == 0 || line.empty()) + } else if (line.find('#') == 0 || line.empty()) { continue; - else if (line.find("BEGIN") == 0 || line.find("begin") == 0) { + } else if (line.find("BEGIN") == 0 || line.find("begin") == 0) { qcir.add_qubits(n_qubit); } else if (line.find("END") == 0 || line.find("end") == 0) { return qcir; diff --git a/src/qsyn/qsyn_helper.cpp b/src/qsyn/qsyn_helper.cpp index c84fecf88..c26140d48 100644 --- a/src/qsyn/qsyn_helper.cpp +++ b/src/qsyn/qsyn_helper.cpp @@ -43,7 +43,7 @@ void create_default_qsynrc(dvlab::CommandLineInterface& cli, std::filesystem::pa namespace fs = std::filesystem; if (!fs::is_directory(qsynrc_path.parent_path()) && !fs::create_directories(qsynrc_path.parent_path())) { - spdlog::critical("Cannot create directory {}", qsynrc_path.parent_path()); + spdlog::critical("Cannot create directory {}", qsynrc_path.parent_path().string()); return; } // clang-format off @@ -115,7 +115,7 @@ bool read_qsynrc_file(dvlab::CommandLineInterface& cli, std::filesystem::path qs cli.clear_history(); if (result == dvlab::CmdExecResult::error) { - spdlog::critical("Some errors occurred while reading the qsynrc file from {}", qsynrc_path); + spdlog::critical("Some errors occurred while reading the qsynrc file from {}", qsynrc_path.string()); return false; } diff --git a/src/tableau/pauli_rotation.hpp b/src/tableau/pauli_rotation.hpp index 66718ac8f..f2ad669bc 100644 --- a/src/tableau/pauli_rotation.hpp +++ b/src/tableau/pauli_rotation.hpp @@ -360,8 +360,14 @@ struct fmt::formatter { constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == '+' || *it == '-' || *it == ' ')) signedness = *it++; - if (it != end && (*it == 'c' || *it == 'b')) presentation = *it++; + if (it != end && (*it == '+' || *it == '-' || *it == ' ')) { + signedness = *it; + it = std::next(it); + } + if (it != end && (*it == 'c' || *it == 'b')) { + presentation = *it; + it = std::next(it); + } if (it != end && *it != '}') detail::throw_format_error("invalid format"); return it; } @@ -383,8 +389,14 @@ struct fmt::formatter { constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == '+' || *it == '-' || *it == ' ')) signedness = *it++; - if (it != end && (*it == 'c' || *it == 'b')) presentation = *it++; + if (it != end && (*it == '+' || *it == '-' || *it == ' ')) { + signedness = *it; + it = std::next(it); + } + if (it != end && (*it == 'c' || *it == 'b')) { + presentation = *it; + it = std::next(it); + } if (it != end && *it != '}') detail::throw_format_error("invalid format"); return it; } diff --git a/src/tableau/stabilizer_tableau.hpp b/src/tableau/stabilizer_tableau.hpp index 524e7315f..8fd92f33b 100644 --- a/src/tableau/stabilizer_tableau.hpp +++ b/src/tableau/stabilizer_tableau.hpp @@ -148,8 +148,12 @@ struct fmt::formatter { char presentation = 'c'; constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == 'c' || *it == 'b')) presentation = *it++; - if (it != end && *it != '}') detail::throw_format_error("invalid format"); + if (it != end && (*it == 'c' || *it == 'b')) { + presentation = *it; + it = std::next(it); + } + if (it != end && *it != '}') + detail::throw_format_error("invalid format"); return it; } diff --git a/src/tableau/tableau.hpp b/src/tableau/tableau.hpp index 2d11ccb07..9d4854d09 100644 --- a/src/tableau/tableau.hpp +++ b/src/tableau/tableau.hpp @@ -103,6 +103,10 @@ class Tableau : public PauliProductTrait { // FIXME - check if the subtableau has the same number of qubits _subtableaux.push_back(subtableau); } + auto push_back(SubTableau&& subtableau) { + // FIXME - check if the subtableau has the same number of qubits + _subtableaux.push_back(std::move(subtableau)); + } template auto emplace_back(Args&&... args) { @@ -159,7 +163,10 @@ struct fmt::formatter { char presentation = 'c'; constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == 'c' || *it == 'b')) presentation = *it++; + if (it != end && (*it == 'c' || *it == 'b')) { + presentation = *it; + it = std::next(it); + } if (it != end && *it != '}') detail::throw_format_error("invalid format"); return it; } @@ -188,7 +195,10 @@ struct fmt::formatter { char presentation = 'c'; constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == 'c' || *it == 'b')) presentation = *it++; + if (it != end && (*it == 'c' || *it == 'b')) { + presentation = *it; + it = std::next(it); + } if (it != end && *it != '}') detail::throw_format_error("invalid format"); return it; } diff --git a/src/tensor/tensor.hpp b/src/tensor/tensor.hpp index 589493781..6ff0bd4ba 100644 --- a/src/tensor/tensor.hpp +++ b/src/tensor/tensor.hpp @@ -232,6 +232,7 @@ Tensor operator/(Tensor lhs, Tensor const& rhs) { template std::vector Tensor
::shape() const { std::vector shape; + shape.reserve(dimension()); for (size_t i = 0; i < dimension(); ++i) { shape.emplace_back(_tensor.shape(i)); } diff --git a/src/util/data_structure_manager_common_cmd.hpp b/src/util/data_structure_manager_common_cmd.hpp index 7c1936be1..7d9d1e6db 100644 --- a/src/util/data_structure_manager_common_cmd.hpp +++ b/src/util/data_structure_manager_common_cmd.hpp @@ -142,8 +142,9 @@ Command mgr_delete_cmd(DataStructureManager& mgr) { mgr.clear(); } else if (!parser.parsed("id")) { mgr.remove(SIZE_MAX); - } else + } else { mgr.remove(parser.get("id")); + } return CmdExecResult::done; }}; diff --git a/src/util/dvlab_string.hpp b/src/util/dvlab_string.hpp index 3ff5e392c..e20af6fc9 100644 --- a/src/util/dvlab_string.hpp +++ b/src/util/dvlab_string.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -79,7 +80,7 @@ namespace views { template requires std::convertible_to || std::convertible_to inline auto split_to_string_views(std::string_view str, DelimT delim) { - return std::views::split(str, delim) | std::views::transform([](auto&& rng) { return std::string_view(&*rng.begin(), std::ranges::distance(rng)); }); + return std::views::split(str, delim) | std::views::transform([](auto&& rng) { return std::string_view(std::ranges::data(rng), std::ranges::distance(rng)); }); } /** @@ -202,7 +203,7 @@ namespace detail { template requires std::integral std::from_chars_result from_chars_wrapper(std::string_view str, T& val) { - return std::from_chars(str.data(), str.data() + str.size(), val); + return std::from_chars(str.data(), std::to_address(str.end()), val); } template @@ -212,13 +213,13 @@ std::from_chars_result from_chars_wrapper(std::string_view str, T& val) { try { if constexpr (std::is_same_v) { val = std::stof(std::string{str}, &pos); - return {str.data() + pos, std::errc{}}; + return {std::next(str.data(), pos), std::errc{}}; } else if constexpr (std::is_same_v) { val = std::stod(std::string{str}, &pos); - return {str.data() + pos, std::errc{}}; + return {std::next(str.data(), pos), std::errc{}}; } else if constexpr (std::is_same_v) { val = std::stold(std::string{str}, &pos); - return {str.data() + pos, std::errc{}}; + return {std::next(str.data(), pos), std::errc{}}; } } catch (std::invalid_argument const& e) { return {str.data(), std::errc::invalid_argument}; @@ -231,7 +232,7 @@ std::from_chars_result from_chars_wrapper(std::string_view str, T& val) { #else template std::from_chars_result from_chars_wrapper(std::string_view str, T& val) { - return std::from_chars(str.data(), str.data() + str.size(), val); + return std::from_chars(str.data(), std::to_address(str.end()), val); } #endif @@ -243,7 +244,7 @@ inline std::optional from_string(std::string_view str) { T result; auto [ptr, ec] = detail::from_chars_wrapper(str, result); - if (ec == std::errc{} && ptr == str.data() + str.size()) { + if (ec == std::errc{} && ptr == std::to_address(str.end())) { return result; } else { // perror(std::make_error_code(ec).message().c_str()); diff --git a/src/util/ordered_hashtable.hpp b/src/util/ordered_hashtable.hpp index 8d6b326e4..e7fadbffd 100644 --- a/src/util/ordered_hashtable.hpp +++ b/src/util/ordered_hashtable.hpp @@ -52,10 +52,14 @@ class ordered_hashtable { // NOLINT(readability-identifier-naming) : ordered_ha template class OTableIterator { + using _itr_val_ref_t = decltype(std::declval()->value()); + public: using value_type = Value; using difference_type = std::ptrdiff_t; using iterator_category = std::bidirectional_iterator_tag; + using reference = std::conditional_t>, value_type const, value_type>&; + OTableIterator() {} OTableIterator(VecIterType const& itr, VecIterType const& begin, VecIterType const& end) : _itr(itr), _begin(begin), _end(end) {} @@ -92,11 +96,16 @@ class ordered_hashtable { // NOLINT(readability-identifier-naming) : ordered_ha bool is_valid() const noexcept { return *(this->_itr) != std::nullopt; } - value_type& operator*() noexcept { return (value_type&)this->_itr->value(); } - value_type& operator*() const noexcept { return (value_type&)this->_itr->value(); } + // reinterpret_cast is intentional: stored_type (e.g. pair) and value_type + // (e.g. pair) are layout-identical but not statically convertible. + // This is the same technique used by libstdc++/libc++ for unordered_map iterators. + // `reference` already carries the correct const-ness from VecIterType, so no + // qualifiers are stripped by either overload. + reference operator*() noexcept { return reinterpret_cast(this->_itr->value()); } // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + reference operator*() const noexcept { return reinterpret_cast(this->_itr->value()); } // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - value_type* operator->() noexcept { return (value_type*)&(this->_itr->value()); } - value_type* operator->() const noexcept { return (value_type*)&(this->_itr->value()); } + auto* operator->() noexcept { return &(**this); } + auto* operator->() const noexcept { return &(**this); } private: VecIterType _itr; diff --git a/src/util/phase.hpp b/src/util/phase.hpp index 587e4ab3c..71fe7b597 100644 --- a/src/util/phase.hpp +++ b/src/util/phase.hpp @@ -250,7 +250,10 @@ struct fmt::formatter { constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { auto it = ctx.begin(), end = ctx.end(); - if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++; + if (it != end && (*it == 'f' || *it == 'e')) { + presentation = *it; + it = std::next(it); + } if (it != end && *it != '}') detail::throw_format_error("invalid format"); return it; } diff --git a/src/util/trie.cpp b/src/util/trie.cpp index 94e353e46..52c0082d0 100644 --- a/src/util/trie.cpp +++ b/src/util/trie.cpp @@ -96,7 +96,7 @@ std::string Trie::shortest_unique_prefix(std::string_view word) const { if (itr->frequency == 1) break; } - return std::string{word.begin(), word.begin() + pos}; + return std::string{word.substr(0, pos)}; } size_t Trie::frequency(std::string_view prefix) const { diff --git a/src/zx/flow/gflow.cpp b/src/zx/flow/gflow.cpp index 2819989f0..b073b5cec 100644 --- a/src/zx/flow/gflow.cpp +++ b/src/zx/flow/gflow.cpp @@ -79,11 +79,12 @@ void GFlow::_initialize() { // NOLINT(readability-make-member-function-const) m if (_zxgraph->is_gadget_leaf(v)) { _measurement_planes[v] = MP::not_a_qubit; _taken.insert(v); - } else if (_zxgraph->is_gadget_axel(v)) + } else if (_zxgraph->is_gadget_axel(v)) { _measurement_planes[v] = v->has_n_pi_phase() ? MP::yz : v->phase().denominator() == 2 ? MP::xz : MP::error; + } assert(_measurement_planes[v] != MP::error); } } diff --git a/src/zx/simplifier/simplify.hpp b/src/zx/simplifier/simplify.hpp index 0b59c5f5f..47c42ac5b 100644 --- a/src/zx/simplifier/simplify.hpp +++ b/src/zx/simplifier/simplify.hpp @@ -87,7 +87,7 @@ size_t simplify(ZXGraph& g, Rule const& rule) { */ template requires std::is_base_of, Rule>::value -size_t hadamard_simplify(ZXGraph& g, Rule rule) { +size_t hadamard_simplify(ZXGraph& g, Rule const& rule) { std::vector match_counts; while (!stop_requested()) {