-
Notifications
You must be signed in to change notification settings - Fork 2
Circuit Optimization Mini-Apps #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @Royschenk, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a new collection of quantum mini-applications focused on circuit optimization, specifically leveraging Dynamic Decoupling (DD) techniques. These mini-apps are designed to evaluate the performance and noise resilience of quantum algorithms like VQA, Circuit Cutting, and QML training when integrated with DD, providing a robust framework for benchmarking middleware in hybrid quantum-classical environments.
Highlights
- New Mini-App Suite: A comprehensive suite of 'Circuit Optimization' mini-apps has been added, designed to explore and benchmark the integration of Dynamic Decoupling (DD) techniques across various quantum computing workflows.
- Dynamic Decoupling Integration: Dynamic Decoupling (DD) techniques are now integrated into existing and new quantum algorithms, including VQA (VQE), Circuit Cutting, and QML training, to evaluate their effectiveness in mitigating noise.
- Performance Benchmarking: The newly added mini-apps provide a robust framework for benchmarking middleware performance (specifically Pilot-Quantum) and assessing the impact of DD under realistic noisy quantum conditions.
- Multi-Framework Support: The mini-apps demonstrate versatility by implementing solutions using both Qiskit and PennyLane, showcasing cross-framework applicability for circuit optimization techniques.
- Comprehensive Documentation and Dependencies: Detailed documentation in
README.mdand arequirements.txtfile have been added to facilitate easy setup, understanding, and execution of the new mini-apps.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
The pull request introduces several new mini-applications demonstrating circuit optimization techniques, specifically Dynamic Decoupling (DD), in conjunction with other quantum computing workflows like Circuit Cutting, QML training, and VQE. The mini-apps leverage the Pilot-Quantum middleware for distributed execution and include noise simulation. The code provides valuable examples for benchmarking these combined techniques. Several areas for improvement were identified, primarily related to code maintainability (hardcoded parameters, redundant code, unused variables/imports), correctness (inconsistent DD application logic, fragile dynamic patching in the QML app, potentially misleading JSD metric in the VQE app), and clarity (lack of comments for complex workarounds). Addressing these points will enhance the robustness, reliability, and clarity of the mini-apps.
| def patch_copula_ansatz_with_dd(): | ||
| """Patch the original copula_ansatz with the DD-enhanced version.""" | ||
| try: | ||
| import qugen.main.generator.quantum_circuits.discrete_generator_pennylane as qgen_circuits | ||
|
|
||
| # Check if copula_ansatz exists in the module | ||
| if hasattr(qgen_circuits, 'copula_ansatz'): | ||
| # Store original function | ||
| original_copula_ansatz = qgen_circuits.copula_ansatz | ||
|
|
||
| # Patch with DD version | ||
| qgen_circuits.copula_ansatz = dd_copula_ansatz | ||
|
|
||
| print("[INFO] Successfully patched copula_ansatz with DD sequence") | ||
| return original_copula_ansatz | ||
| else: | ||
| print("[WARNING] copula_ansatz not found in qgen_circuits module") | ||
| # Create and patch a new function if it doesn't exist | ||
| qgen_circuits.copula_ansatz = dd_copula_ansatz | ||
| print("[INFO] Created new copula_ansatz function with DD sequence") | ||
| return regular_copula_ansatz | ||
|
|
||
| except ImportError as e: | ||
| print(f"[ERROR] Cannot import from qugen.main.generator.quantum_circuits: {e}") | ||
| print("[INFO] Will use local implementation of copula_ansatz") | ||
| # No patching performed, will use our local implementation | ||
| return regular_copula_ansatz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamically patching functions in external libraries (qugen) is a fragile approach. It creates a strong dependency on the internal structure and naming of qugen. If qugen is updated or refactored, this patching mechanism is likely to break. A more robust approach would be to define the ansatz function directly within this mini-app or pass the desired ansatz function (either DD-enabled or regular) as a parameter to the training logic, avoiding runtime modification of imported modules.
| def expvals_to_probs(expvals): | ||
| # Convert single-qubit Z expectations to probabilities of states | ||
| single_probs = [[(1 + ez)/2, (1 - ez)/2] for ez in expvals] | ||
|
|
||
| # Simplified approach: use product state approximation | ||
| n_states = 2**len(expvals) | ||
| all_probs = np.zeros(n_states) | ||
|
|
||
| for state_idx in range(n_states): | ||
| # Convert index to bit string | ||
| bitstring = format(state_idx, f'0{len(expvals)}b') | ||
|
|
||
| # Calculate probability of this bitstring | ||
| prob = 1.0 | ||
| for q_idx, bit in enumerate(bitstring): | ||
| bit_val = int(bit) | ||
| prob *= single_probs[q_idx][bit_val] | ||
|
|
||
| all_probs[state_idx] = prob | ||
|
|
||
| return all_probs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JSD calculation uses a 'Simplified approach: use product state approximation' based on single-qubit Z expectation values. This approximation might not accurately reflect the true state fidelity or JSD, especially for entangled states, and could lead to misleading conclusions about DD effectiveness. For a Master's thesis, a more rigorous metric like fidelity or true JSD based on state vectors (if simulation allows) or full probability distributions might be necessary. If this approximation is used, its limitations should be clearly documented.
| else: | ||
| print("[WARNING] copula_ansatz not found in qgen_circuits module") | ||
| # Create and patch a new function if it doesn't exist | ||
| qgen_circuits.copula_ansatz = dd_copula_ansatz | ||
| print("[INFO] Created new copula_ansatz function with DD sequence") | ||
| return regular_copula_ansatz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback logic here (returning regular_copula_ansatz if patching fails) means that if the qugen import or attribute access fails, the experiment will silently run without DD, even if use_dd=True was intended. This can lead to misleading results. Consider raising a more prominent warning or error if the intended DD ansatz cannot be applied due to patching failure.
| for d in range(1, depth + 1): | ||
| for i in range(0, n_qubits - 1, 2): | ||
| qml.CNOT(wires=[wires[i], wires[i+1]]) | ||
| qml.QubitChannel(get_phase_damping_kraus(0.05), wires=wires[i+1]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # Optional final DD | ||
| for q in range(num_qubits): | ||
| idle_time = current_layer - last_gate_layer[q] | ||
| if last_gate_layer[q] != -1 and idle_time > 1: | ||
| print(f"[DD] Final DD on qubit {q} at end (idle for {idle_time} layers)") | ||
| for gate in dd_sequence: | ||
| new_circuit.append(gate, [q]) | ||
| new_circuit.barrier(q) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def vqe_ansatz(params: np.ndarray, wires: List[int], use_dd: bool = False, dd_inserted: bool = False) -> None: | ||
| n_qubits = len(wires) | ||
| n_layers = params.shape[0] | ||
|
|
||
| # Apply parameterized rotations and entangling layers | ||
| for layer in range(n_layers): | ||
| # Rotation layer | ||
| param_width = params.shape[1] | ||
| for i in range(n_qubits): | ||
| if i*3 + 2 >= param_width: | ||
| break # prevent out-of-bounds access | ||
| qml.RY(params[layer, i*3], wires=wires[i]) | ||
| qml.RZ(params[layer, i*3+1], wires=wires[i]) | ||
| qml.RY(params[layer, i*3+2], wires=wires[i]) | ||
|
|
||
| # Entangling layer | ||
| for i in range(n_qubits): | ||
| qml.CNOT(wires=[wires[i], wires[(i+1) % n_qubits]]) | ||
|
|
||
| # Apply DD sequence if enabled and not already inserted | ||
| if use_dd and not dd_inserted: | ||
| #print(f"[DEBUG] Inserting DD sequence on wires {wires}") | ||
| apply_dd_sequence(wires) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def apply_noise(wires: List[int], noise_level: float = 0.05) -> None: | ||
| for wire in wires: | ||
| qml.QubitChannel(get_phase_damping_kraus(noise_level), wires=wire) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for q in range(num_qubits): | ||
| if q in involved_qubits: | ||
| idle_time = current_layer - last_gate_layer[q] | ||
| if last_gate_layer[q] != -1 and idle_time > 1: #aanpassen naar 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| # Get all results | ||
| results = self.executor.get_results(futures) | ||
| end_time = time.time() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| parameters={ | ||
| 'n_qubits': 2, # H2 molecule typically needs 2 qubits | ||
| 'circuit_depth': 2, | ||
| 'max_steps': 25, # Reduce for faster execution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Royschenk - can you revert deletions happened in qml_training & quantum_simulation folders.
|
@Royschenk - also, do we need all the png & notebook files? or can they be created when we run the experiment scripts, if so lets delete them and keep only the necessary scripts. Notebook files, if they are already scripted, then probably they are duplicates and can be removed from the repo. |
|
And can you paste an example output execution of the scripts with fresh installation - so the scripts are manualy tested. |
Adding Circuit Optimization (CO) Mini-Apps, including VQA + CO, Circuit Cutting + CO, QML-training + CO, and base VQA (VQE) + two base CO (Dynamic Decoupling) Mini-Apps