Skip to content

Instantly share code, notes, and snippets.

@PhDP
Last active January 27, 2018 18:37
Show Gist options
  • Save PhDP/474dfc28ed911b32b79a57d997ee1db3 to your computer and use it in GitHub Desktop.
Save PhDP/474dfc28ed911b32b79a57d997ee1db3 to your computer and use it in GitHub Desktop.
C++17 sum-types version of a quantum circuit model for a 2-bit demultiplexer. It's like the object-oriented version, but it doesn't suck.
// With gcc 7+ or clang 5+, compiles with -std=c++17 flag
#include <iostream>
#include <variant>
#include <vector>
struct toffoli_gate {
uint32_t c0, c1, x;
toffoli_gate(uint32_t c0_, uint32_t c1_, uint32_t x_) noexcept
: c0(c0_), c1(c1_), x(x_) {
}
auto apply(std::vector<bool>& bits) const -> void {
if (bits[c0] && bits[c1]) bits[x] = !bits[x];
}
auto print(std::ostream& os) const -> std::ostream& {
os << "toffoli(" << c0 << ',' << c1 << ',' << x << ')';
return os;
};
};
struct fredkin_gate {
uint32_t c, a, b;
fredkin_gate(uint32_t c_, uint32_t a_, uint32_t b_) noexcept
: c(c_), a(a_), b(b_) {
}
auto apply(std::vector<bool>& bits) const -> void {
if (bits[c]) {
// std::vector<bool>'s operator() returns values so std::swap would fail.
auto const old_a = bits[a]; // The xor trick would do too...
bits[a] = bits[b];
bits[b] = old_a;
}
}
auto print(std::ostream& os) const -> std::ostream& {
os << "fredkin(" << c << ',' << a << ',' << b << ')';
return os;
};
};
struct not_gate {
uint32_t x;
not_gate(uint32_t x_) noexcept : x(x_) { }
auto apply(std::vector<bool>& bits) const -> void {
bits[x] = !bits[x];
}
auto print(std::ostream& os) const -> std::ostream& {
os << "not(" << x << ')';
return os;
};
};
struct cnot_gate {
uint32_t c, x;
cnot_gate(uint32_t c_, uint32_t x_) noexcept : c(c_), x(x_) { }
auto apply(std::vector<bool>& bits) const -> void {
if (bits[c]) bits[x] = !bits[x];
}
auto print(std::ostream& os) const -> std::ostream& {
os << "cnot(" << c << ',' << x << ')';
return os;
};
};
struct swap_gate {
uint32_t a, b;
swap_gate(uint32_t a_, uint32_t b_) noexcept : a(a_), b(b_) { }
auto apply(std::vector<bool>& bits) const -> void {
auto const old_a = bits[a];
bits[a] = bits[b];
bits[b] = old_a;
}
auto print(std::ostream& os) const -> std::ostream& {
os << "swap(" << a << ',' << b << ')';
return os;
};
};
using gate = std::variant<
not_gate,
cnot_gate,
swap_gate,
toffoli_gate,
fredkin_gate
>;
// Can store directly in a vector because it's not fucking pointers to a base class:
using gates = std::vector<gate>;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
auto apply_gates(std::vector<bool> const& bits, gates const& gs) -> std::vector<bool> {
auto new_bits = bits;
for (auto const& g : gs) {
std::visit([&new_bits](auto const& x) { x.apply(new_bits); }, g);
}
return new_bits;
}
auto operator<<(std::ostream& os, gate const& g) -> std::ostream& {
return std::visit([&os](auto const& v) -> std::ostream& { return v.print(os); }, g);
}
int main() {
// std::cout << "sizeof(toffoli_gate): " << sizeof(toffoli_gate) << "\n"
// << "sizeof(gate): " << sizeof(gate) << "\n\n";
// 2-bit demultiplexer:
auto one_hot = gates{};
one_hot.push_back(toffoli_gate(0, 1, 3));
one_hot.push_back(cnot_gate(0, 1));
one_hot.push_back(not_gate(0));
one_hot.push_back(toffoli_gate(0, 1, 2));
one_hot.push_back(cnot_gate(2, 0));
one_hot.push_back(cnot_gate(2, 1));
std::cout << "2-bit demultiplexer:\n";
for (auto const& g : one_hot) std::cout << " " << g << '\n';
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment