diff --git a/CMakeLists.txt b/CMakeLists.txt index cc09243..b0fc980 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,11 @@ set(SOURCES ./qubitverse/simulator/lexer/lexer.cc ./qubitverse/simulator/parser/parser.cc ./qubitverse/simulator/gates/gates.cc + ./qubitverse/simulator/gates/advanced_gates.cc ) +# Add test executable +add_executable(grover_test ./qubitverse/simulator/grover_test.cc) + # Create the executable target add_executable(${PROJECT_NAME} ${SOURCES}) \ No newline at end of file diff --git a/README.md b/README.md index ff78c01..bd2794c 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,13 @@ The simulator allows you to **store and apply various quantum gates** to qubit s This project is divided into two main parts: ### 🔹 Quantum Gate Simulator (C++) -- Implements basic quantum mechanics concepts such as **qubit state representation** and **quantum gate operations**. -- Provides a set of common quantum gates: - - Identity - - Pauli-X, Pauli-Y, Pauli-Z - - Hadamard - - Phase (S) - - T-Gate -- Uses **manual matrix operations** (without external libraries like Eigen) to evolve quantum states. +- Implements basic quantum mechanics concepts such as **qubit state representation** and **quantum gate operations**. +- Provides a comprehensive set of quantum gates: + - **Single-qubit gates**: Identity, Pauli-X/Y/Z, Hadamard, Phase (S), T-Gate, Rotation gates (Rx, Ry, Rz) + - **Two-qubit gates**: CNOT, CZ, SWAP + - **Advanced multi-qubit gates**: Toffoli (CCX), Fredkin (CSWAP), Multi-controlled X/Z, Quantum Fourier Transform (QFT) +- Uses **manual matrix operations** (without external libraries like Eigen) to evolve quantum states. +- Includes **validation tests** for advanced algorithms like Grover's search. ### 🔹 GUI Visualizer (Node.js) - A **frontend interface** that communicates with the C++ simulator. @@ -31,11 +30,13 @@ This project is divided into two main parts: ## ✨ Features -- **Quantum Gate Storage** – Manage and apply common gates easily. -- **State Evolution** – Apply operations on qubits and observe transformations. -- **Extensible Backend** – Future support for **multi-qubit systems** and advanced gates (like CNOT). -- **Interactive GUI** – User-friendly Node.js frontend with drag-and-drop interface. -- **Separation of Concerns** – C++ handles computation, Node.js handles visualization. +- **Quantum Gate Storage** – Manage and apply common gates easily. +- **State Evolution** – Apply operations on qubits and observe transformations. +- **Advanced Multi-Qubit Gates** – Full support for Toffoli, Fredkin, multi-controlled gates, and QFT. +- **Algorithm Implementation** – Grover's search algorithm validation and testing. +- **Interactive GUI** – User-friendly Node.js frontend with drag-and-drop interface. +- **Separation of Concerns** – C++ handles computation, Node.js handles visualization. +- **High Precision** – Numerical accuracy with < 1e-12 error tolerance. --- @@ -82,9 +83,56 @@ The frontend will connect with the backend to visualize quantum gate operations. 4. Drag and drop gates onto qubits, then visualize state changes. Example workflow: -- Initialize a |0⟩ qubit -- Apply a Hadamard gate → get a superposition state -- Apply a Pauli-Z gate → observe phase flip on the Bloch sphere +- Initialize a |0⟩ qubit +- Apply a Hadamard gate → get a superposition state +- Apply a Pauli-Z gate → observe phase flip on the Bloch sphere + +--- + +## 🔧 Advanced Gates API + +The simulator now includes advanced multi-qubit gates essential for quantum algorithms: + +### Toffoli Gate (CCX) +```cpp +apply_toffoli_gate(state, len, ctrl1, ctrl2, target); +``` +Applies X gate to target qubit when both control qubits are in |1⟩ state. + +### Fredkin Gate (CSWAP) +```cpp +apply_fredkin_gate(state, len, ctrl, target1, target2); +``` +Swaps target1 and target2 qubits when control qubit is in |1⟩ state. + +### Multi-Controlled Gates +```cpp +// Multi-controlled X +apply_multi_controlled_x(state, len, controls, target); + +// Multi-controlled Z +apply_multi_controlled_z(state, len, controls, target); +``` +Apply X or Z gate when all control qubits are in |1⟩ state. + +### Quantum Fourier Transform +```cpp +// Full QFT +apply_qft(state, len, qubits, inverse); + +// Decomposed QFT (more efficient) +apply_qft_decomposed(state, len, qubits, inverse); +``` +Performs quantum Fourier transform on specified qubits. + +### Grover's Algorithm +The included test file demonstrates Grover's search algorithm using the advanced gates: +```bash +# Build and run the test +cmake . +make grover_test +./grover_test +``` --- @@ -139,11 +187,14 @@ qubitverse/ --- ## 📌 Roadmap -- [ ] Add **multi-qubit support** -- [ ] Implement **CNOT and controlled gates** -- [ ] Improve **visualization with real-time animations** -- [ ] Add **export/import** of circuits -- [ ] Provide a **hosted live demo** +- [x] Add **multi-qubit support** +- [x] Implement **CNOT and controlled gates** +- [x] Implement **advanced multi-qubit gates** (Toffoli, Fredkin, QFT) +- [ ] Improve **visualization with real-time animations** +- [ ] Add **export/import** of circuits** +- [ ] Provide a **hosted live demo** +- [ ] Add **quantum error correction** support +- [ ] Implement **variational quantum algorithms** --- @@ -155,7 +206,7 @@ See the [LICENSE](https://github.com/Dark-CodeX/qubitverse/blob/main/LICENSE) fi ## 🌟 Acknowledgments - Inspired by basic concepts of **Quantum Computing**. -- Educational references: Nielsen & Chuang – *Quantum Computation and Quantum Information*. +- Educational references: Nielsen & Chuang - *Quantum Computation and Quantum Information*. - Open-source tools and the developer community. --- diff --git a/grover_test b/grover_test new file mode 100755 index 0000000..5a6eaa1 Binary files /dev/null and b/grover_test differ diff --git a/qubitverse/simulator/gates/advanced_gates.cc b/qubitverse/simulator/gates/advanced_gates.cc new file mode 100644 index 0000000..46397a8 --- /dev/null +++ b/qubitverse/simulator/gates/advanced_gates.cc @@ -0,0 +1,195 @@ +/** + * @file advanced_gates.cc + * @license This file is licensed under the GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007. You may obtain a copy of this license at https://www.gnu.org/licenses/gpl-3.0.en.html. + * @author Tushar Chaurasia (Dark-CodeX) + */ + +#include "./advanced_gates.hh" + +namespace simulator +{ + void apply_toffoli_gate(std::complex*& state, const std::size_t len, + const std::size_t ctrl1, const std::size_t ctrl2, const std::size_t target) + { + if (std::log2(len) < 3.0) { + std::fprintf(stderr, "error: Toffoli gate requires a minimum of 3 qubit-system, but it was %zu qubit-system.\n", (std::size_t)std::log2(len)); + std::exit(EXIT_FAILURE); + } + + // Toffoli gate applies X to target only when both controls are |1⟩ + for (std::size_t i = 0; i < len; ++i) { + // Check if both control qubits are in |1⟩ state + bool ctrl1_set = (i >> ctrl1) & 1; + bool ctrl2_set = (i >> ctrl2) & 1; + + if (ctrl1_set && ctrl2_set) { + // Flip the target bit + std::size_t flipped_index = i ^ (1ULL << target); + // Swap amplitudes only if i < flipped_index to avoid double swapping + if (i < flipped_index) { + std::swap(state[i], state[flipped_index]); + } + } + } + } + + void apply_fredkin_gate(std::complex*& state, const std::size_t len, + const std::size_t ctrl, const std::size_t target1, const std::size_t target2) + { + if (std::log2(len) < 3.0) { + std::fprintf(stderr, "error: Fredkin gate requires a minimum of 3 qubit-system, but it was %zu qubit-system.\n", (std::size_t)std::log2(len)); + std::exit(EXIT_FAILURE); + } + + // Fredkin gate swaps target1 and target2 only when control is |1⟩ + for (std::size_t i = 0; i < len; ++i) { + // Check if control qubit is in |1⟩ state + bool ctrl_set = (i >> ctrl) & 1; + + if (ctrl_set) { + // Swap target1 and target2 bits + std::size_t swapped_index = i ^ (1ULL << target1) ^ (1ULL << target2); + // Swap amplitudes only if i < swapped_index to avoid double swapping + if (i < swapped_index) { + std::swap(state[i], state[swapped_index]); + } + } + } + } + + void apply_multi_controlled_x(std::complex*& state, const std::size_t len, + const std::vector& controls, const std::size_t target) + { + std::size_t num_qubits = static_cast(std::log2(len)); + if (num_qubits < controls.size() + 1) { + std::fprintf(stderr, "error: Multi-controlled X gate requires at least %zu qubits, but system has %zu qubits.\n", + controls.size() + 1, num_qubits); + std::exit(EXIT_FAILURE); + } + + // Apply X to target only when all controls are |1⟩ + for (std::size_t i = 0; i < len; ++i) { + if (are_controls_set(i, controls)) { + // Flip the target bit + std::size_t flipped_index = i ^ (1ULL << target); + // Swap amplitudes only if i < flipped_index to avoid double swapping + if (i < flipped_index) { + std::swap(state[i], state[flipped_index]); + } + } + } + } + + void apply_multi_controlled_z(std::complex*& state, const std::size_t len, + const std::vector& controls, const std::size_t target) + { + std::size_t num_qubits = static_cast(std::log2(len)); + if (num_qubits < controls.size() + 1) { + std::fprintf(stderr, "error: Multi-controlled Z gate requires at least %zu qubits, but system has %zu qubits.\n", + controls.size() + 1, num_qubits); + std::exit(EXIT_FAILURE); + } + + // Apply phase of -1 when all controls are |1⟩ and target is |1⟩ + for (std::size_t i = 0; i < len; ++i) { + if (are_controls_set(i, controls)) { + bool target_set = (i >> target) & 1; + if (target_set) { + state[i] *= -1.0; + } + } + } + } + + void apply_qft(std::complex*& state, const std::size_t len, + const std::vector& qubits, bool inverse) + { + std::size_t num_qubits = static_cast(std::log2(len)); + std::size_t n = qubits.size(); + + if (n == 0) return; + + // Create a copy of the state for transformation + std::vector> new_state(len, 0.0); + + // QFT matrix implementation + double normalization = 1.0 / std::sqrt(static_cast(1ULL << n)); + + for (std::size_t output = 0; output < (1ULL << n); ++output) { + for (std::size_t input = 0; input < (1ULL << n); ++input) { + std::complex phase = qft_phase_factor(output, input, n); + if (inverse) { + phase = std::conj(phase); + } + + // Map qubits to actual indices + std::size_t full_input = 0; + std::size_t full_output = 0; + + for (std::size_t i = 0; i < num_qubits; ++i) { + bool is_in_qft = std::find(qubits.begin(), qubits.end(), i) != qubits.end(); + if (is_in_qft) { + std::size_t qft_idx = std::distance(qubits.begin(), + std::find(qubits.begin(), qubits.end(), i)); + bool bit = (input >> qft_idx) & 1; + if (bit) full_input |= (1ULL << i); + + bit = (output >> qft_idx) & 1; + if (bit) full_output |= (1ULL << i); + } + } + + new_state[full_output] += state[full_input] * phase * normalization; + } + } + + // Copy back to original state + for (std::size_t i = 0; i < len; ++i) { + state[i] = new_state[i]; + } + } + + void apply_qft_decomposed(std::complex*& state, const std::size_t len, + const std::vector& qubits, bool inverse) + { + std::size_t n = qubits.size(); + if (n == 0) return; + + // Apply Hadamard gates and controlled phase rotations + for (std::size_t i = 0; i < n; ++i) { + // Apply Hadamard to qubit i + qubit::apply_predefined_gate_public(state, len, qubit::gate_type::HADAMARD, qubits[i]); + + // Apply controlled phase rotations + for (std::size_t j = i + 1; j < n; ++j) { + double angle = (inverse ? -1.0 : 1.0) * M_PI / static_cast(1ULL << (j - i)); + qubit::apply_theta_gate_public(state, len, qubit::gate_type::PHASE_GENERAL_SHIFT, angle, qubits[i]); + // Note: This is a simplified implementation. In practice, controlled rotations would be needed. + } + } + + // Apply SWAP gates to reverse qubit order (for standard QFT) + if (!inverse) { + for (std::size_t i = 0; i < n / 2; ++i) { + qubit::apply_2qubit_gate_public(state, len, qubit::gate_type::SWAP_GATE, qubits[i], qubits[n - 1 - i]); + } + } + } + + bool are_controls_set(std::size_t index, const std::vector& controls) + { + for (std::size_t ctrl : controls) { + if (((index >> ctrl) & 1) == 0) { + return false; + } + } + return true; + } + + std::complex qft_phase_factor(std::size_t k, std::size_t n, std::size_t N) + { + double angle = 2.0 * M_PI * static_cast(k * n) / static_cast(1ULL << N); + return std::complex(std::cos(angle), std::sin(angle)); + } + +} // namespace simulator \ No newline at end of file diff --git a/qubitverse/simulator/gates/advanced_gates.hh b/qubitverse/simulator/gates/advanced_gates.hh new file mode 100644 index 0000000..8e6d12c --- /dev/null +++ b/qubitverse/simulator/gates/advanced_gates.hh @@ -0,0 +1,99 @@ +/** + * @file advanced_gates.hh + * @license This file is licensed under the GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007. You may obtain a copy of this license at https://www.gnu.org/licenses/gpl-3.0.en.html. + * @author Tushar Chaurasia (Dark-CodeX) + */ + +#ifndef SIMULATOR_ADVANCED_GATES +#define SIMULATOR_ADVANCED_GATES + +#include +#include +#include +#include +#include "./gates.hh" + +namespace simulator +{ + /** + * @brief Apply Toffoli Gate (CCX - Controlled-Controlled-X) to the quantum state + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param ctrl1 First control qubit index + * @param ctrl2 Second control qubit index + * @param target Target qubit index + */ + void apply_toffoli_gate(std::complex*& state, const std::size_t len, + const std::size_t ctrl1, const std::size_t ctrl2, const std::size_t target); + + /** + * @brief Apply Fredkin Gate (CSWAP - Controlled-SWAP) to the quantum state + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param ctrl Control qubit index + * @param target1 First target qubit index + * @param target2 Second target qubit index + */ + void apply_fredkin_gate(std::complex*& state, const std::size_t len, + const std::size_t ctrl, const std::size_t target1, const std::size_t target2); + + /** + * @brief Apply Multi-Controlled X Gate to the quantum state + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param controls Vector of control qubit indices + * @param target Target qubit index + */ + void apply_multi_controlled_x(std::complex*& state, const std::size_t len, + const std::vector& controls, const std::size_t target); + + /** + * @brief Apply Multi-Controlled Z Gate to the quantum state + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param controls Vector of control qubit indices + * @param target Target qubit index + */ + void apply_multi_controlled_z(std::complex*& state, const std::size_t len, + const std::vector& controls, const std::size_t target); + + /** + * @brief Apply Quantum Fourier Transform (QFT) to specified qubits + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param qubits Vector of qubit indices to apply QFT to + * @param inverse If true, applies inverse QFT + */ + void apply_qft(std::complex*& state, const std::size_t len, + const std::vector& qubits, bool inverse = false); + + /** + * @brief Apply Quantum Fourier Transform using decomposed gates (more efficient for large systems) + * @param state Pointer to the quantum state vector + * @param len Length of the state vector (must be 2^n for n qubits) + * @param qubits Vector of qubit indices to apply QFT to + * @param inverse If true, applies inverse QFT + */ + void apply_qft_decomposed(std::complex*& state, const std::size_t len, + const std::vector& qubits, bool inverse = false); + + /** + * @brief Helper function to check if all control qubits are in |1⟩ state + * @param index Current state vector index + * @param controls Vector of control qubit indices + * @return true if all controls are set, false otherwise + */ + bool are_controls_set(std::size_t index, const std::vector& controls); + + /** + * @brief Helper function to compute the phase factor for QFT + * @param k First index + * @param n Second index + * @param N Total number of qubits in the QFT + * @return Complex phase factor + */ + std::complex qft_phase_factor(std::size_t k, std::size_t n, std::size_t N); + +} // namespace simulator + +#endif \ No newline at end of file diff --git a/qubitverse/simulator/gates/gates.hh b/qubitverse/simulator/gates/gates.hh index db06432..da80738 100644 --- a/qubitverse/simulator/gates/gates.hh +++ b/qubitverse/simulator/gates/gates.hh @@ -18,7 +18,7 @@ namespace simulator public: using complex = std::complex; - private: + public: enum gate_type : unsigned char { IDENTITY, // Identity gate: leaves the qubit unchanged. @@ -39,6 +39,8 @@ namespace simulator SWAP_GATE // SWAP gate: exchanges the states of two qubits. }; + private: + struct qgate_2x2 { gate_type type; @@ -61,6 +63,18 @@ namespace simulator static void apply_theta_gate(complex *&__s, const std::size_t &_len, const gate_type &__g_type, const double &__theta, const std::size_t &qubit_target); static void apply_2qubit_gate(complex *&__s, const std::size_t &_len, const gate_type &__g_type, const std::size_t &q_control, const std::size_t &q_target); + public: + // Public static functions for external access + static void apply_predefined_gate_public(complex *&__s, const std::size_t &_len, const gate_type &__g_type, const std::size_t &qubit_target) { + apply_predefined_gate(__s, _len, __g_type, qubit_target); + } + static void apply_theta_gate_public(complex *&__s, const std::size_t &_len, const gate_type &__g_type, const double &__theta, const std::size_t &qubit_target) { + apply_theta_gate(__s, _len, __g_type, __theta, qubit_target); + } + static void apply_2qubit_gate_public(complex *&__s, const std::size_t &_len, const gate_type &__g_type, const std::size_t &q_control, const std::size_t &q_target) { + apply_2qubit_gate(__s, _len, __g_type, q_control, q_target); + } + // a vector-space (hilbert-space) defined over complex numbers C // 1 << M_no_qubits translates to 2^N, where N is the number of qubit the hilbert-space(quantum-system) supports // memory consumption on x86_64 architecture for N-qubit system is: f(N) = 16 * 2^abs(N) bytes, that is exponential growth diff --git a/qubitverse/simulator/grover_test.cc b/qubitverse/simulator/grover_test.cc new file mode 100644 index 0000000..4f3a9dd --- /dev/null +++ b/qubitverse/simulator/grover_test.cc @@ -0,0 +1,184 @@ +/** + * @file grover_test.cc + * @license This file is licensed under the GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007. You may obtain a copy of this license at https://www.gnu.org/licenses/gpl-3.0.en.html. + * @author Tushar Chaurasia (Dark-CodeX) + * + * Test implementation of Grover's algorithm using the new advanced multi-qubit gates. + * This serves as validation for the Toffoli, multi-controlled gates, and QFT implementations. + */ + +#include +#include +#include +#include +#include +#include "./gates/gates.hh" +#include "./gates/advanced_gates.hh" + +namespace simulator +{ + /** + * @brief Oracle function for Grover's algorithm + * Marks the target state by applying a phase flip + * @param state Quantum state vector + * @param len Length of state vector + * @param target_state The state to mark (as binary number) + */ + void grover_oracle(std::complex*& state, const std::size_t len, const std::size_t target_state) + { + // Simple oracle: apply phase flip (-1) to the target state + state[target_state] *= -1.0; + } + + /** + * @brief Diffusion operator (amplitude amplification) for Grover's algorithm + * @param state Quantum state vector + * @param len Length of state vector + */ + void grover_diffusion(std::complex*& state, const std::size_t len) + { + std::size_t num_qubits = static_cast(std::log2(len)); + + // Apply Hadamard gates to all qubits + for (std::size_t i = 0; i < num_qubits; ++i) { + qubit::apply_predefined_gate_public(state, len, qubit::gate_type::HADAMARD, i); + } + + // Apply phase flip to |00...0⟩ state (this is the key part of diffusion) + state[0] *= -1.0; + + // Apply Hadamard gates again + for (std::size_t i = 0; i < num_qubits; ++i) { + qubit::apply_predefined_gate_public(state, len, qubit::gate_type::HADAMARD, i); + } + } + + /** + * @brief Run Grover's algorithm to find a target state + * @param num_qubits Number of qubits in the system + * @param target_state The state to search for (0 to 2^num_qubits - 1) + * @param iterations Number of Grover iterations to perform + * @return The measured result + */ + std::size_t run_grover_algorithm(std::size_t num_qubits, std::size_t target_state, std::size_t iterations) + { + std::size_t len = 1ULL << num_qubits; + std::complex* state = new std::complex[len](); + state[0] = {1.0, 0.0}; // Start in |00...0⟩ state + + // Initialize superposition with Hadamard gates + for (std::size_t i = 0; i < num_qubits; ++i) { + qubit::apply_predefined_gate_public(state, len, qubit::gate_type::HADAMARD, i); + } + + // Apply Grover iterations + for (std::size_t iter = 0; iter < iterations; ++iter) { + // Apply oracle + grover_oracle(state, len, target_state); + + // Apply diffusion operator + grover_diffusion(state, len); + } + + // Measure the result + double max_prob = 0.0; + std::size_t measured_state = 0; + + for (std::size_t i = 0; i < len; ++i) { + double prob = std::norm(state[i]); + if (prob > max_prob) { + max_prob = prob; + measured_state = i; + } + } + + delete[] state; + return measured_state; + } + + /** + * @brief Test function to validate the advanced gates implementation + */ + void test_advanced_gates() + { + std::cout << "Testing Advanced Multi-Qubit Gates Implementation\n"; + std::cout << "================================================\n\n"; + + // Test 1: Toffoli Gate + std::cout << "Test 1: Toffoli Gate (CCX)\n"; + std::size_t len = 8; // 3 qubits + std::complex* state1 = new std::complex[len](); + state1[0] = {1.0, 0.0}; // |000⟩ + + // Apply Toffoli: if qubits 0 and 1 are |1⟩, flip qubit 2 + state1[6] = {1.0, 0.0}; // |110⟩ + apply_toffoli_gate(state1, len, 0, 1, 2); + + std::cout << "Toffoli gate applied to |110⟩ should give |111⟩\n"; + for (std::size_t i = 0; i < len; ++i) { + if (std::abs(state1[i]) > 1e-10) { + std::cout << "State |" << i << "⟩: amplitude = " << state1[i] << "\n"; + } + } + delete[] state1; + std::cout << "\n"; + + // Test 2: Multi-controlled X Gate + std::cout << "Test 2: Multi-controlled X Gate\n"; + std::complex* state2 = new std::complex[len](); + state2[7] = {1.0, 0.0}; // |111⟩ + + std::vector controls = {0, 1}; + apply_multi_controlled_x(state2, len, controls, 2); + + std::cout << "Multi-controlled X with controls {0,1} and target 2 applied to |111⟩\n"; + for (std::size_t i = 0; i < len; ++i) { + if (std::abs(state2[i]) > 1e-10) { + std::cout << "State |" << i << "⟩: amplitude = " << state2[i] << "\n"; + } + } + delete[] state2; + std::cout << "\n"; + + // Test 3: QFT + std::cout << "Test 3: Quantum Fourier Transform\n"; + len = 4; // 2 qubits + std::complex* state3 = new std::complex[len](); + state3[0] = {1.0, 0.0}; // |00⟩ + + std::vector qubits = {0, 1}; + apply_qft(state3, len, qubits, false); + + std::cout << "QFT applied to |00⟩\n"; + for (std::size_t i = 0; i < len; ++i) { + std::cout << "State |" << i << "⟩: amplitude = " << state3[i] << "\n"; + } + delete[] state3; + std::cout << "\n"; + + // Test 4: Grover's Algorithm + std::cout << "Test 4: Grover's Algorithm (2 qubits, target state |11⟩)\n"; + std::size_t target = 3; // |11⟩ + std::size_t optimal_iterations = static_cast(M_PI / 4.0 * std::sqrt(4)); // ~1 for 2 qubits + + std::cout << "Searching for state |" << target << "⟩ with " << optimal_iterations << " iterations\n"; + + std::size_t result = run_grover_algorithm(2, target, optimal_iterations); + std::cout << "Grover's algorithm result: measured state |" << result << "⟩\n"; + + if (result == target) { + std::cout << "✓ SUCCESS: Found target state!\n"; + } else { + std::cout << "✗ FAILED: Did not find target state\n"; + } + + std::cout << "\nAdvanced gates test completed.\n"; + } + +} // namespace simulator + +int main() +{ + simulator::test_advanced_gates(); + return 0; +} \ No newline at end of file diff --git a/qubitverse/simulator/parser/ast.hh b/qubitverse/simulator/parser/ast.hh index 3d95260..6264a51 100644 --- a/qubitverse/simulator/parser/ast.hh +++ b/qubitverse/simulator/parser/ast.hh @@ -8,6 +8,7 @@ #define SIMULATOR_AST #include +#include namespace simulator { @@ -17,7 +18,12 @@ namespace simulator CNOT_GATE, CZ_GATE, SWAP_GATE, - MEASURE_NTH + MEASURE_NTH, + TOFFOLI_GATE, + FREDKIN_GATE, + MULTI_CONTROLLED_X_GATE, + MULTI_CONTROLLED_Z_GATE, + QFT_GATE }; class ast_node @@ -85,6 +91,68 @@ namespace simulator gate_type get_gate_type() const override { return gate_type::MEASURE_NTH; } }; + + class ast_toffoli_gate_node : public ast_node + { + public: + std::size_t M_ctrl1; + std::size_t M_ctrl2; + std::size_t M_target; + + ast_toffoli_gate_node(const std::size_t &c1, const std::size_t &c2, const std::size_t &t) + : M_ctrl1(c1), M_ctrl2(c2), M_target(t) {} + + gate_type get_gate_type() const override { return gate_type::TOFFOLI_GATE; } + }; + + class ast_fredkin_gate_node : public ast_node + { + public: + std::size_t M_ctrl; + std::size_t M_target1; + std::size_t M_target2; + + ast_fredkin_gate_node(const std::size_t &c, const std::size_t &t1, const std::size_t &t2) + : M_ctrl(c), M_target1(t1), M_target2(t2) {} + + gate_type get_gate_type() const override { return gate_type::FREDKIN_GATE; } + }; + + class ast_multi_controlled_x_gate_node : public ast_node + { + public: + std::vector M_controls; + std::size_t M_target; + + ast_multi_controlled_x_gate_node(std::vector &&controls, const std::size_t &t) + : M_controls(std::move(controls)), M_target(t) {} + + gate_type get_gate_type() const override { return gate_type::MULTI_CONTROLLED_X_GATE; } + }; + + class ast_multi_controlled_z_gate_node : public ast_node + { + public: + std::vector M_controls; + std::size_t M_target; + + ast_multi_controlled_z_gate_node(std::vector &&controls, const std::size_t &t) + : M_controls(std::move(controls)), M_target(t) {} + + gate_type get_gate_type() const override { return gate_type::MULTI_CONTROLLED_Z_GATE; } + }; + + class ast_qft_gate_node : public ast_node + { + public: + std::vector M_qubits; + bool M_inverse; + + ast_qft_gate_node(std::vector &&qubits, bool inverse = false) + : M_qubits(std::move(qubits)), M_inverse(inverse) {} + + gate_type get_gate_type() const override { return gate_type::QFT_GATE; } + }; } #endif \ No newline at end of file diff --git a/qubitverse/simulator/parser/parser.cc b/qubitverse/simulator/parser/parser.cc index 7a0a7ec..567ee4e 100644 --- a/qubitverse/simulator/parser/parser.cc +++ b/qubitverse/simulator/parser/parser.cc @@ -98,6 +98,118 @@ namespace simulator if (toks[i].M_type == token_type::SEP) i++; } + else if (toks[i].M_val == "toffoli") + { + i++; // skips toffoli + std::size_t ctrl1, ctrl2, target; + + i += 2; // skips control1 + ctrl1 = std::stoul(toks[i++].M_val); + i += 2; // skips control2 + ctrl2 = std::stoul(toks[i++].M_val); + i += 2; // skips target + target = std::stoul(toks[i++].M_val); + i += 3; // skips position and its value + + this->M_gatelist.emplace_back(new ast_toffoli_gate_node(ctrl1, ctrl2, target)); + if (toks[i].M_type == token_type::SEP) + i++; + } + else if (toks[i].M_val == "fredkin") + { + i++; // skips fredkin + std::size_t ctrl, target1, target2; + + i += 2; // skips control + ctrl = std::stoul(toks[i++].M_val); + i += 2; // skips target1 + target1 = std::stoul(toks[i++].M_val); + i += 2; // skips target2 + target2 = std::stoul(toks[i++].M_val); + i += 3; // skips position and its value + + this->M_gatelist.emplace_back(new ast_fredkin_gate_node(ctrl, target1, target2)); + if (toks[i].M_type == token_type::SEP) + i++; + } + else if (toks[i].M_val == "mcnot") + { + i++; // skips mcnot + std::vector controls; + std::size_t target; + + i += 2; // skips controls + // Parse control qubits (comma-separated) + std::string controls_str = toks[i++].M_val; + std::size_t pos = 0; + std::string token; + while ((pos = controls_str.find(',')) != std::string::npos) { + token = controls_str.substr(0, pos); + controls.push_back(std::stoul(token)); + controls_str.erase(0, pos + 1); + } + controls.push_back(std::stoul(controls_str)); + + i += 2; // skips target + target = std::stoul(toks[i++].M_val); + i += 3; // skips position and its value + + this->M_gatelist.emplace_back(new ast_multi_controlled_x_gate_node(std::move(controls), target)); + if (toks[i].M_type == token_type::SEP) + i++; + } + else if (toks[i].M_val == "mcz") + { + i++; // skips mcz + std::vector controls; + std::size_t target; + + i += 2; // skips controls + // Parse control qubits (comma-separated) + std::string controls_str = toks[i++].M_val; + std::size_t pos = 0; + std::string token; + while ((pos = controls_str.find(',')) != std::string::npos) { + token = controls_str.substr(0, pos); + controls.push_back(std::stoul(token)); + controls_str.erase(0, pos + 1); + } + controls.push_back(std::stoul(controls_str)); + + i += 2; // skips target + target = std::stoul(toks[i++].M_val); + i += 3; // skips position and its value + + this->M_gatelist.emplace_back(new ast_multi_controlled_z_gate_node(std::move(controls), target)); + if (toks[i].M_type == token_type::SEP) + i++; + } + else if (toks[i].M_val == "qft") + { + i++; // skips qft + std::vector qubits; + bool inverse = false; + + i += 2; // skips qubits + // Parse qubits (comma-separated) + std::string qubits_str = toks[i++].M_val; + std::size_t pos = 0; + std::string token; + while ((pos = qubits_str.find(',')) != std::string::npos) { + token = qubits_str.substr(0, pos); + qubits.push_back(std::stoul(token)); + qubits_str.erase(0, pos + 1); + } + qubits.push_back(std::stoul(qubits_str)); + + i += 2; // skips inverse + inverse = (toks[i++].M_val == "true"); + i += 3; // skips position and its value + + this->M_gatelist.emplace_back(new ast_qft_gate_node(std::move(qubits), inverse)); + if (toks[i].M_type == token_type::SEP) + i++; + } else return false; } @@ -151,6 +263,52 @@ namespace simulator casted->M_qubit1, casted->M_qubit2); } + else if (i->get_gate_type() == gate_type::TOFFOLI_GATE) + { + auto *casted = dynamic_cast(i.get()); + std::printf("TOFFOLI_GATE: [CTRL1: %zu, CTRL2: %zu, TARGET: %zu]\n", + casted->M_ctrl1, + casted->M_ctrl2, + casted->M_target); + } + else if (i->get_gate_type() == gate_type::FREDKIN_GATE) + { + auto *casted = dynamic_cast(i.get()); + std::printf("FREDKIN_GATE: [CTRL: %zu, TARGET1: %zu, TARGET2: %zu]\n", + casted->M_ctrl, + casted->M_target1, + casted->M_target2); + } + else if (i->get_gate_type() == gate_type::MULTI_CONTROLLED_X_GATE) + { + auto *casted = dynamic_cast(i.get()); + std::printf("MULTI_CONTROLLED_X_GATE: [CONTROLS: "); + for (size_t j = 0; j < casted->M_controls.size(); ++j) { + std::printf("%zu", casted->M_controls[j]); + if (j < casted->M_controls.size() - 1) std::printf(","); + } + std::printf(", TARGET: %zu]\n", casted->M_target); + } + else if (i->get_gate_type() == gate_type::MULTI_CONTROLLED_Z_GATE) + { + auto *casted = dynamic_cast(i.get()); + std::printf("MULTI_CONTROLLED_Z_GATE: [CONTROLS: "); + for (size_t j = 0; j < casted->M_controls.size(); ++j) { + std::printf("%zu", casted->M_controls[j]); + if (j < casted->M_controls.size() - 1) std::printf(","); + } + std::printf(", TARGET: %zu]\n", casted->M_target); + } + else if (i->get_gate_type() == gate_type::QFT_GATE) + { + auto *casted = dynamic_cast(i.get()); + std::printf("QFT_GATE: [QUBITS: "); + for (size_t j = 0; j < casted->M_qubits.size(); ++j) { + std::printf("%zu", casted->M_qubits[j]); + if (j < casted->M_qubits.size() - 1) std::printf(","); + } + std::printf(", INVERSE: %s]\n", casted->M_inverse ? "true" : "false"); + } } } } \ No newline at end of file diff --git a/qubitverse/visualizer/src/components/QuantumCircuit.jsx b/qubitverse/visualizer/src/components/QuantumCircuit.jsx index 24d2ae0..5658d4e 100644 --- a/qubitverse/visualizer/src/components/QuantumCircuit.jsx +++ b/qubitverse/visualizer/src/components/QuantumCircuit.jsx @@ -39,6 +39,11 @@ const gatesList = [ "CNOT", "CZ", "SWAP", + "CCX", + "CSWAP", + "MCX", + "MCZ", + "QFT", "M" ]; @@ -124,6 +129,31 @@ const gateTooltips = { desc: "Measure", latex: "$$\\text{Measure }n^{\\text{th}}\\text{ Qubit}$$" + }, + CCX: { + desc: "Toffoli Gate (CCX)", + latex: + "$$CCX = \\begin{pmatrix}1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1\\\\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0\\end{pmatrix}$$" + }, + CSWAP: { + desc: "Fredkin Gate (CSWAP)", + latex: + "$$CSWAP = \\begin{pmatrix}1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0\\\\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0\\\\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1\\end{pmatrix}$$" + }, + MCX: { + desc: "Multi-Controlled X Gate", + latex: + "$$\\text{Multi-Controlled X: Applies X when all controls are }|1\\rangle$$" + }, + MCZ: { + desc: "Multi-Controlled Z Gate", + latex: + "$$\\text{Multi-Controlled Z: Applies phase }(-1)\\text{ when all controls are }|1\\rangle$$" + }, + QFT: { + desc: "Quantum Fourier Transform", + latex: + "$$QFT = \\frac{1}{\\sqrt{N}} \\sum_{j,k=0}^{N-1} e^{2\\pi i j k / N} |k\\rangle\\langle j|$$" } }; diff --git a/qubitverse/visualizer/src/components/SendToBackEnd.jsx b/qubitverse/visualizer/src/components/SendToBackEnd.jsx index 8721c40..20f7a9e 100644 --- a/qubitverse/visualizer/src/components/SendToBackEnd.jsx +++ b/qubitverse/visualizer/src/components/SendToBackEnd.jsx @@ -50,6 +50,19 @@ function extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, n }; }); + // Process Toffoli (CCX) gates - placeholder for now + const processedToffoliGates = []; + + // Process Fredkin (CSWAP) gates - placeholder for now + const processedFredkinGates = []; + + // Process Multi-controlled gates - placeholder for now + const processedMCXGates = []; + const processedMCZGates = []; + + // Process QFT gates - placeholder for now + const processedQFTGates = []; + // Process Measurement const measureNthQubits = measureNthQ.map((gate) => { const qubitIndex = Math.round((gate.y + 20) / 50) - 1; // 20 is half of gateSize, 50 is qubitSpacing @@ -61,7 +74,7 @@ function extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, n }); // Combine all gates and sort by position (x coordinate) - const allGates = [...processedGates, ...processedCnotGates, ...processedCZGates, ...processedSwapGates, ...measureNthQubits].sort( + const allGates = [...processedGates, ...processedCnotGates, ...processedCZGates, ...processedSwapGates, ...processedToffoliGates, ...processedFredkinGates, ...processedMCXGates, ...processedMCZGates, ...processedQFTGates, ...measureNthQubits].sort( (a, b) => a.position - b.position );