32 #ifndef CLASSES_REVERSIBLE_H 33 #define CLASSES_REVERSIBLE_H 42 class Dynamic_bitset :
public IDisplay {
44 using value_type =
unsigned int;
45 using storage_type = std::vector<value_type>;
49 std::vector<value_type> v_;
57 idx index_(idx pos)
const {
return pos / (
sizeof(value_type) * CHAR_BIT); }
67 idx offset_(idx pos)
const {
return pos % (
sizeof(value_type) * CHAR_BIT); }
75 explicit Dynamic_bitset(idx n)
76 : storage_size_{n / (
sizeof(value_type) * CHAR_BIT) + 1}, n_{n},
82 virtual ~Dynamic_bitset() =
default;
91 const storage_type& data()
const {
return v_; }
98 idx size() const noexcept {
return n_; }
106 idx storage_size() const noexcept {
return storage_size_; }
113 idx count() const noexcept {
115 idx bitset_size = size();
116 for (idx i = 0; i < bitset_size; ++i) {
130 bool get(idx pos)
const noexcept {
131 return 1 & (v_[index_(pos)] >> offset_(pos));
139 bool none() const noexcept {
141 idx bitset_storage_size = storage_size();
142 for (idx i = 0; i < bitset_storage_size; ++i) {
156 bool all() const noexcept {
158 idx bitset_storage_size = storage_size();
159 for (idx i = 0; i < bitset_storage_size; ++i) {
173 bool any() const noexcept {
return !(none()); }
183 Dynamic_bitset&
set(idx pos,
bool value =
true) {
184 value ? v_[index_(pos)] |= (1 << offset_(pos))
185 : v_[index_(pos)] &= ~(1 << offset_(pos));
197 Dynamic_bitset&
set() noexcept {
198 idx bitset_storage_size = storage_size();
199 for (idx i = 0; i < bitset_storage_size; ++i) {
214 Dynamic_bitset& rand(idx pos,
double p = 0.5) {
215 std::random_device rd;
216 std::mt19937 gen{rd()};
217 std::bernoulli_distribution d{p};
230 Dynamic_bitset& rand(
double p = 0.5) {
231 idx bitset_size = size();
232 for (idx i = 0; i < bitset_size; ++i) {
245 Dynamic_bitset& reset(idx pos) {
246 v_[index_(pos)] &= ~(1 << offset_(pos));
256 Dynamic_bitset& reset() noexcept {
257 idx bitset_storage_size = storage_size();
258 for (idx i = 0; i < bitset_storage_size; ++i) {
271 Dynamic_bitset& flip(idx pos) {
272 v_[index_(pos)] ^= 1 << (offset_(pos));
282 Dynamic_bitset& flip() noexcept {
283 idx bitset_storage_size = storage_size();
284 for (idx i = 0; i < bitset_storage_size; ++i) {
298 bool operator==(
const Dynamic_bitset& rhs)
const noexcept {
299 assert(size() == rhs.size());
301 idx n = std::min(storage_size(), rhs.storage_size());
302 for (idx i = 0; i < n; ++i) {
303 if (v_[i] != rhs.v_[i]) {
317 bool operator!=(
const Dynamic_bitset& rhs)
const noexcept {
318 return !(*
this == rhs);
328 idx operator-(
const Dynamic_bitset& rhs)
const noexcept {
330 idx bitset_size = size();
331 for (idx i = 0; i < bitset_size; ++i) {
332 if (
get(i) != rhs.get(i))
350 template <
class CharT =
char,
class Traits = std::
char_traits<CharT>,
351 class Allocator = std::allocator<CharT>>
352 std::basic_string<CharT, Traits, Allocator>
353 to_string(CharT zero = CharT(
'0'), CharT one = CharT(
'1'))
const {
354 std::basic_string<CharT, Traits, Allocator> result;
355 idx bitset_size = size();
356 result.resize(bitset_size);
358 for (idx i = bitset_size; i-- > 0;) {
360 result[bitset_size - i - 1] = zero;
362 result[bitset_size - i - 1] = one;
379 std::ostream& display(std::ostream& os)
const override {
380 idx bitset_size = size();
381 for (idx i = bitset_size; i-- > 0;) {
393 class Bit_circuit :
public Dynamic_bitset,
public IJSON {
394 std::unordered_map<std::string, idx> count_{};
395 std::unordered_map<std::string, idx> depth_{};
396 Dynamic_bitset bNOT_, bCNOT_, bSWAP_, bTOF_, bFRED_,
405 explicit Bit_circuit(idx n)
406 : Dynamic_bitset{n}, bNOT_{n}, bCNOT_{n}, bSWAP_{n}, bTOF_{n},
407 bFRED_{n}, btotal_{n} {}
414 explicit Bit_circuit(
const Dynamic_bitset& dynamic_bitset)
415 : Dynamic_bitset{dynamic_bitset}, bNOT_{size()}, bCNOT_{size()},
416 bSWAP_{size()}, bTOF_{size()}, bFRED_{size()}, btotal_{size()} {}
425 Bit_circuit& X(idx i) {
434 virtual ~Bit_circuit() =
default;
443 Bit_circuit& NOT(idx i) {
446 ++count_[__FILE__
"__total__"];
449 if (count_[
"NOT"] == 1)
454 if (bNOT_.get(i) ==
false) {
456 bNOT_ = Dynamic_bitset{n_};
463 if (count_[__FILE__
"__total__"] == 1)
464 depth_[__FILE__
"__total__"] = 1;
468 if (btotal_.get(i) ==
false) {
470 btotal_ = Dynamic_bitset{n_};
473 ++depth_[__FILE__
"__total__"];
486 Bit_circuit& CNOT(idx ctrl, idx target) {
487 v_[index_(target)] ^= (1 & (v_[index_(ctrl)] >> offset_(ctrl)))
490 ++count_[__FILE__
"__total__"];
493 if (count_[
"CNOT"] == 1)
496 bCNOT_.flip(ctrl).flip(target);
498 if (bCNOT_.get(ctrl) ==
false || bCNOT_.get(target) ==
false) {
500 bCNOT_ = Dynamic_bitset{n_};
502 bCNOT_.set(ctrl).set(target);
507 if (count_[__FILE__
"__total__"] == 1)
508 depth_[__FILE__
"__total__"] = 1;
510 btotal_.flip(ctrl).flip(target);
512 if (btotal_.get(ctrl) ==
false || btotal_.get(target) ==
false) {
514 btotal_ = Dynamic_bitset{n_};
516 btotal_.set(ctrl).set(target);
517 ++depth_[__FILE__
"__total__"];
531 Bit_circuit& TOF(idx i, idx j, idx k) {
532 v_[index_(k)] ^= ((1 & (v_[index_(j)] >> offset_(j))) &
533 (1 & (v_[index_(i)] >> offset_(i))))
536 ++count_[__FILE__
"__total__"];
539 if (count_[
"TOF"] == 1)
542 bTOF_.flip(i).flip(j).flip(k);
544 if (bTOF_.get(i) ==
false || bTOF_.get(j) ==
false ||
545 bTOF_.get(k) ==
false) {
547 bTOF_ = Dynamic_bitset{n_};
549 bTOF_.set(i).set(j).set(k);
554 if (count_[__FILE__
"__total__"] == 1)
555 depth_[__FILE__
"__total__"] = 1;
557 btotal_.flip(i).flip(j).flip(k);
559 if (btotal_.get(i) ==
false || btotal_.get(j) ==
false ||
560 btotal_.get(k) ==
false) {
562 btotal_ = Dynamic_bitset{n_};
564 btotal_.set(i).set(j).set(k);
565 ++depth_[__FILE__
"__total__"];
578 Bit_circuit& SWAP(idx i, idx j) {
579 if (
get(i) !=
get(j)) {
584 ++count_[__FILE__
"__total__"];
587 if (count_[
"SWAP"] == 1)
590 bSWAP_.flip(i).flip(j);
592 if (bSWAP_.get(i) ==
false || bSWAP_.get(j) ==
false) {
594 bSWAP_ = Dynamic_bitset{n_};
596 bSWAP_.set(i).set(j);
601 if (count_[__FILE__
"__total__"] == 1)
602 depth_[__FILE__
"__total__"] = 1;
604 btotal_.flip(i).flip(j);
606 if (btotal_.get(i) ==
false || btotal_.get(j) ==
false) {
608 btotal_ = Dynamic_bitset{n_};
610 btotal_.set(i).set(j);
611 ++depth_[__FILE__
"__total__"];
625 Bit_circuit& FRED(idx i, idx j, idx k) {
630 ++count_[__FILE__
"__total__"];
633 if (count_[
"FRED"] == 1)
636 bFRED_.flip(i).flip(j).flip(k);
638 if (bFRED_.get(i) ==
false || bFRED_.get(j) ==
false ||
639 bFRED_.get(k) ==
false) {
641 bFRED_ = Dynamic_bitset{n_};
643 bFRED_.set(i).set(j).set(k);
648 if (count_[__FILE__
"__total__"] == 1)
649 depth_[__FILE__
"__total__"] = 1;
651 btotal_.flip(i).flip(j).flip(k);
653 if (btotal_.get(i) ==
false || btotal_.get(j) ==
false ||
654 btotal_.get(k) ==
false) {
656 btotal_ = Dynamic_bitset{n_};
658 btotal_.set(i).set(j).set(k);
659 ++depth_[__FILE__
"__total__"];
670 Bit_circuit& reset() noexcept {
673 Dynamic_bitset::reset();
685 idx get_gate_count(
const std::string& name)
const {
692 result = count_.at(
"NOT");
694 result = count_.at(name);
708 idx get_gate_count()
const {
714 result = count_.at(__FILE__
"__total__");
729 idx get_gate_depth(
const std::string& name)
const {
736 result = depth_.at(
"NOT");
738 result = depth_.at(name);
752 idx get_gate_depth()
const {
758 result = depth_.at(__FILE__
"__total__");
778 std::string to_JSON(
bool enclosed_in_curly_brackets =
true)
const override {
781 if (enclosed_in_curly_brackets)
784 result +=
"\"n\" : " + std::to_string(n_);
786 ", \"total gate count\" : " + std::to_string(get_gate_count());
788 ", \"total gate depth\" : " + std::to_string(get_gate_depth());
789 result +=
", \"bit state\" : \"" + this->to_string() +
'\"';
790 result +=
", \"Hamming weight\" : " + std::to_string(count());
792 if (enclosed_in_curly_brackets)
807 std::ostream& display(std::ostream& os)
const override {
808 os <<
"n = " << n_ <<
'\n';
809 os <<
"total gate count: " << get_gate_count() <<
'\n';
810 os <<
"total gate depth: " << get_gate_depth() <<
'\n';
811 os <<
"bit state: " << this->to_string() <<
'\n';
812 os <<
"Hamming weight: " << count();
Quantum++ main namespace.
Definition: circuits.h:35