Skip to content
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

v1.2.0 #92

Merged
merged 184 commits into from
Dec 31, 2024
Merged

v1.2.0 #92

merged 184 commits into from
Dec 31, 2024

Conversation

amachino
Copy link
Owner

@amachino amachino commented Dec 21, 2024

Summary by CodeRabbit

  • New Features

    • Introduced new Jupyter notebooks for simulating 3D rotations and Rabi oscillations.
    • Added functionality for drag pulse calibration and cross-resonance calibration in quantum systems.
    • Enhanced the PulseSchedule class to support a more structured representation of targets.
    • Added new methods for Hamiltonian calculations in the QuantumSystem class.
    • Updated the Experiment class methods to simplify parameter handling and introduced new methods for state tomography and population dynamics.
    • Introduced new methods in the StateManager class to improve configurability and state handling.
    • Added new functions for saving figures and improved plotting capabilities in the visualization module.
    • Updated the workflow configuration for building and testing the Python package.
    • Changed the licensing terms from GNU GPL Version 3 to Apache License Version 2.0.
    • Added new class methods for 180-degree rotations in the Clifford class.
    • Introduced the CrossResonance class for managing cross-resonance pulse schedules.
  • Bug Fixes

    • Improved error handling in various classes and methods related to pulse generation and measurement.
  • Documentation

    • Updated README with installation instructions and added new sections for clarity.
    • Enhanced Jupyter notebooks with updated method calls and parameters for clarity.
  • Style

    • Standardized naming conventions and formatting across multiple files for consistency.
  • Tests

    • Updated test cases to reflect changes in the structure of the PulseSchedule class and other functionalities.
  • Chores

    • Updated dependencies in pyproject.toml and versioning in version.py.

shmokmt and others added 30 commits November 7, 2024 12:47
…ate vector plotting functionality in simulation results
…d enhance pulse scheduling with frequency and object annotations
…nction parameters and improve control signal handling
…function and improve visualization with Plotly
…and visualization; update example notebook
…nsistency; update return types and downsampling logic
…ons; enhance simulation parameters and plotting
…y; remove cross_resonance_2 example notebook
…ethods; fix parameter naming in waveform plotting
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
docs/examples/simulator/8_cr_calibration.ipynb (5)

41-64: Consider documenting parameter ranges and constraints.

While units are documented, it would be helpful to add comments explaining:

  • Valid ranges for parameters
  • Physical constraints
  • Reasoning behind chosen values (e.g., why 0.333 for anharmonicity)

112-123: Add docstring and type hints for return value normalization.

The drag_pi_pulse function performs pulse normalization but lacks documentation explaining the normalization factor calculation.

Add comprehensive documentation:

 def drag_pi_pulse(
     duration: float,
     anharmonicity: float = anharmonicity,
 ) -> qp.Pulse:
+    """Generate a normalized DRAG pulse for pi rotation.
+    
+    Args:
+        duration: Pulse duration in ns
+        anharmonicity: Qubit anharmonicity in GHz
+        
+    Returns:
+        qp.Pulse: Normalized DRAG pulse with pi rotation area
+        
+    Note:
+        The pulse is normalized such that its area equals pi,
+        ensuring a complete pi rotation when applied.
+    """

242-287: Add progress tracking for long simulations.

The simulate_cr function could benefit from progress tracking during simulation.

Consider adding a progress callback:

 def simulate_cr(
     control_drive_frequency: float,
     target_drive_frequency: float,
     cr_amplitude: float,
     cr_duration: float,
     cr_ramptime: float,
     cr_phase: float,
     crosstalk_amplitude: float = 0.0,
     crosstalk_phase: float = 0.0,
     cancel_amplitude: float = 0.0,
     cancel_phase: float = 0.0,
     echo: bool = False,
     control_state: str = "0",
     n_samples: int = 256,
     plot: bool = False,
+    progress_callback: Optional[Callable[[float], None]] = None,
 ) -> SimulationResult:

336-430: Consider caching intermediate results for performance.

The hamiltonian_tomography function performs multiple simulations that could benefit from caching.

Consider adding result caching:

from functools import lru_cache

@lru_cache(maxsize=32)
def _cached_simulate_cr(*args, **kwargs) -> SimulationResult:
    return simulate_cr(*args, **kwargs)

793-835: Add convergence monitoring to optimization.

The CMA-ES optimization could benefit from convergence monitoring and logging.

Consider adding a callback:

def optimization_callback(es):
    """Monitor optimization progress."""
    if es.countiter % 10 == 0:
        print(f"Iteration {es.countiter}: Best score = {es.best.f}")

Then add it to the optimizer:

 es = cma.CMAEvolutionStrategy(
     initial_guess,
     1.0,
     {
         "seed": 42,
         "ftarget": 1e-6,
         "timeout": 120,
+        "verb_disp": 10,  # Display progress every 10 iterations
         ...
     },
 )
-es.optimize(objective_func)
+es.optimize(objective_func, callback=optimization_callback)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6dfeae1 and eda71b1.

📒 Files selected for processing (1)
  • docs/examples/simulator/8_cr_calibration.ipynb (1 hunks)
🔇 Additional comments (3)
docs/examples/simulator/8_cr_calibration.ipynb (3)

9-32: LGTM! Imports are well-organized.

The imports are appropriate for quantum simulation work and follow standard conventions. The use of autoreload is helpful for development.


73-103: LGTM! System configuration is well-structured.

The quantum system setup is clear and follows a logical structure with appropriate parameter passing.


739-784: 🛠️ Refactor suggestion

Enhance objective function robustness.

The objective_func implementation could be improved:

  1. Add bounds checking
  2. Handle simulation failures gracefully
  3. Add early stopping for invalid parameters
 def objective_func(x: np.ndarray):
+    """Calculate infidelity with bounds checking and error handling.
+    
+    Returns:
+        float: Infidelity value or infinity for invalid parameters
+    """
     (
         cr_phase,
         cancel_amplitude,
         cancel_phase,
     ) = x
+    
+    # Check bounds
+    if not (-np.pi <= cr_phase <= np.pi and 
+            -1 <= cancel_amplitude <= 1 and 
+            -np.pi <= cancel_phase <= np.pi):
+        return float('inf')
+    
+    try:
         result_0 = simulate_cr(...)
         result_1 = simulate_cr(...)
+    except Exception as e:
+        print(f"Simulation failed: {e}")
+        return float('inf')

Likely invalid or redundant comment.

Comment on lines +152 to +233
"def cr_sequence(\n",
" control_drive_frequency: float,\n",
" target_drive_frequency: float,\n",
" cr_amplitude: float,\n",
" cr_duration: float,\n",
" cr_ramptime: float,\n",
" cr_phase: float,\n",
" crosstalk_amplitude: float = 0.0,\n",
" crosstalk_phase: float = 0.0,\n",
" cancel_amplitude: float = 0.0,\n",
" cancel_phase: float = 0.0,\n",
" echo: bool = False,\n",
"):\n",
" cr_waveform = qp.FlatTop(\n",
" duration=cr_duration,\n",
" amplitude=2 * np.pi * cr_amplitude,\n",
" tau=cr_ramptime,\n",
" phase_shift=cr_phase,\n",
" )\n",
" cancel_waveform = qp.FlatTop(\n",
" duration=cr_duration,\n",
" amplitude=2 * np.pi * cancel_amplitude,\n",
" tau=cr_ramptime,\n",
" phase_shift=cancel_phase,\n",
" )\n",
" crosstalk_waveform = qp.FlatTop(\n",
" duration=cr_duration,\n",
" amplitude=2 * np.pi * crosstalk_amplitude,\n",
" tau=cr_ramptime,\n",
" phase_shift=crosstalk_phase,\n",
" )\n",
" with qp.PulseSchedule(\n",
" {\n",
" \"CR\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": control_qubit_label,\n",
" },\n",
" \"Crosstalk\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": target_qubit_label,\n",
" },\n",
" \"Target\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": target_qubit_label,\n",
" },\n",
" }\n",
" ) as cr:\n",
" cr.add(\"CR\", cr_waveform)\n",
" cr.add(\"Target\", cancel_waveform)\n",
" cr.add(\"Crosstalk\", crosstalk_waveform)\n",
"\n",
" if not echo:\n",
" return cr\n",
" else:\n",
" with qp.PulseSchedule(\n",
" {\n",
" \"Control\": {\n",
" \"frequency\": control_drive_frequency,\n",
" \"object\": control_qubit_label,\n",
" },\n",
" \"CR\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": control_qubit_label,\n",
" },\n",
" \"Crosstalk\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": target_qubit_label,\n",
" },\n",
" \"Target\": {\n",
" \"frequency\": target_drive_frequency,\n",
" \"object\": target_qubit_label,\n",
" },\n",
" }\n",
" ) as ecr:\n",
" ecr.call(cr)\n",
" ecr.barrier()\n",
" ecr.add(\"Control\", pi_pulse)\n",
" ecr.barrier()\n",
" ecr.call(cr.scaled(-1))\n",
" ecr.barrier()\n",
" ecr.add(\"Control\", pi_pulse)\n",
" return ecr"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for invalid parameters.

The cr_sequence function should validate input parameters before creating pulses.

Add parameter validation:

 def cr_sequence(
     control_drive_frequency: float,
     target_drive_frequency: float,
     cr_amplitude: float,
     cr_duration: float,
     cr_ramptime: float,
     cr_phase: float,
     crosstalk_amplitude: float = 0.0,
     crosstalk_phase: float = 0.0,
     cancel_amplitude: float = 0.0,
     cancel_phase: float = 0.0,
     echo: bool = False,
 ):
+    """Create a cross-resonance pulse sequence.
+    
+    Args: [...]
+    Raises:
+        ValueError: If parameters are invalid
+    """
+    if cr_duration <= 0 or cr_ramptime <= 0:
+        raise ValueError("Duration and ramp time must be positive")
+    if cr_ramptime * 2 > cr_duration:
+        raise ValueError("Ramp time too large compared to duration")
+    if not 0 <= cr_amplitude <= 1:
+        raise ValueError("CR amplitude must be between 0 and 1")

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/qubex/analysis/fitting.py (1)

1687-1687: ⚠️ Potential issue

Fix mutable default argument.

Using a mutable object (numpy array) as a default argument can lead to unexpected behavior since the same array object is shared between function calls.

Apply this fix:

-def fit_rotation(
-    times: npt.NDArray[np.float64],
-    data: npt.NDArray[np.float64],
-    r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
+def fit_rotation(
+    times: npt.NDArray[np.float64],
+    data: npt.NDArray[np.float64],
+    r0: npt.NDArray[np.float64] | None = None,

Then initialize the default value within the function:

    if r0 is None:
        r0 = np.array([0, 0, 1])
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🧹 Nitpick comments (1)
src/qubex/analysis/fitting.py (1)

260-359: Add error handling for polynomial fitting.

While the function handles root finding errors well, it should also handle potential errors during polynomial fitting.

Apply this improvement:

-    popt = np.polyfit(x, y, degree)
-    fun = np.poly1d(popt)
-    y_fit = fun(x)
+    try:
+        popt = np.polyfit(x, y, degree)
+        fun = np.poly1d(popt)
+        y_fit = fun(x)
+    except (ValueError, np.linalg.LinAlgError) as e:
+        print(f"Failed to fit polynomial for {target}: {str(e)}")
+        return {
+            "popt": None,
+            "fun": None,
+            "root": None,
+            "fig": None,
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eda71b1 and ae92a32.

📒 Files selected for processing (1)
  • src/qubex/analysis/fitting.py (35 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
src/qubex/analysis/fitting.py

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (4)
src/qubex/analysis/fitting.py (4)

214-238: LGTM! Well-implemented square root Lorentzian function.

The implementation is mathematically correct and includes proper type hints and documentation.


1684-1928: LGTM! Well-implemented 3D rotation fitting function.

The implementation includes:

  • Proper error handling and input validation
  • Efficient parameter estimation using FFT
  • Comprehensive 2D and 3D visualizations
  • Clear documentation and type hints
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


521-521: LGTM! Improved return types for better maintainability.

The change from tuples to dictionaries makes the return values more explicit and easier to extend in the future.

Also applies to: 618-618, 753-753, 1249-1249, 1472-1472


615-615: LGTM! Improved consistency in axis labels.

The standardization of y-axis titles from "Amplitude (arb. units)" to "Signal (arb. unit)" improves the consistency of the visualization outputs.

Also applies to: 750-750, 1246-1246, 1356-1356

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/qubex/analysis/fitting.py (1)

1687-1687: ⚠️ Potential issue

Fix mutable default argument.

Using a mutable object (numpy array) as a default argument can lead to unexpected behavior since the same array object is shared between function calls.

Apply this fix:

-def fit_rotation(
-    times: npt.NDArray[np.float64],
-    data: npt.NDArray[np.float64],
-    r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
+def fit_rotation(
+    times: npt.NDArray[np.float64],
+    data: npt.NDArray[np.float64],
+    r0: npt.NDArray[np.float64] | None = None,

Then initialize the default value within the function:

    if r0 is None:
        r0 = np.array([0, 0, 1])
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🧹 Nitpick comments (1)
src/qubex/analysis/fitting.py (1)

260-359: Add error handling for polynomial fitting.

While the implementation is good, it should handle potential fitting failures gracefully, similar to other fitting functions in the module.

Apply this improvement:

-    popt = np.polyfit(x, y, degree)
-    fun = np.poly1d(popt)
-    y_fit = fun(x)
+    try:
+        popt = np.polyfit(x, y, degree)
+        fun = np.poly1d(popt)
+        y_fit = fun(x)
+    except (ValueError, np.linalg.LinAlgError) as e:
+        print(f"Failed to fit polynomial: {str(e)}")
+        return {
+            "popt": None,
+            "fun": None,
+            "root": None,
+            "fig": None,
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae92a32 and dda7482.

📒 Files selected for processing (1)
  • src/qubex/analysis/fitting.py (35 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
src/qubex/analysis/fitting.py

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (4)
src/qubex/analysis/fitting.py (4)

214-238: LGTM! Well-implemented square root Lorentzian function.

The implementation is mathematically correct and follows best practices with proper type hints and documentation.


488-495: LGTM! Good plot enhancement.

The added frequency annotation improves the plot's readability and provides important information directly on the visualization.


1684-1929: LGTM! Excellent implementation of 3D rotation fitting.

The implementation is mathematically sound with:

  • Proper handling of rotation matrices
  • Good initial parameter estimation using FFT
  • Well-designed 2D and 3D visualizations
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


521-521: LGTM! Good improvement in return types.

The change from tuples to dictionaries makes the return values more explicit and self-documenting, improving code maintainability and readability.

Also applies to: 538-539, 618-618, 649-650, 753-754, 784-785, 1472-1472, 1493-1494

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/qubex/analysis/fitting.py (1)

1684-1694: ⚠️ Potential issue

Fix mutable default argument.

Using a mutable object (numpy array) as a default argument can lead to unexpected behavior since the same array object is shared between function calls.

Apply this fix:

 def fit_rotation(
     times: npt.NDArray[np.float64],
     data: npt.NDArray[np.float64],
-    r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
+    r0: npt.NDArray[np.float64] | None = None,
     p0=None,
     bounds=None,
     plot: bool = True,
     title: str = "State evolution",
     xlabel: str = "Time (ns)",
     ylabel: str = "Expectation value",
 ) -> dict:

Then initialize the default value within the function:

    if r0 is None:
        r0 = np.array([0, 0, 1])
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

src/qubex/analysis/visualization.py (1)

18-53: 🛠️ Refactor suggestion

Additional improvements needed for the save_figure_image function

While the previous review already covered input validation, there are additional improvements needed:

  1. Add return type hint (-> None)
  2. Validate format parameter matches the file extension
  3. Use atomic file operations to handle race conditions
 def save_figure_image(
     fig: go.Figure,
     name: str = "image",
     *,
     images_dir: str = "./images",
     format: Literal["png", "svg", "jpeg", "webp"] = "png",
     width: int = 600,
     height: int = 300,
     scale: int = 3,
-):
+) -> None:
+    if not format in ["png", "svg", "jpeg", "webp"]:
+        raise ValueError(f"Unsupported format: {format}")
+
     if not os.path.exists(images_dir):
-        os.makedirs(images_dir)
+        os.makedirs(images_dir, exist_ok=True)

     counter = 1
     current_date = datetime.datetime.now().strftime("%Y%m%d")
-    file_path = os.path.join(
-        images_dir,
-        f"{current_date}_{name}_{counter}.{format}",
-    )
-
-    while os.path.exists(file_path):
+    while True:
+        file_path = os.path.join(
+            images_dir,
+            f"{current_date}_{name}_{counter}.{format}",
+        )
+        try:
+            # Try to create file exclusively
+            fd = os.open(file_path, os.O_CREAT | os.O_EXCL)
+            os.close(fd)
+            break
+        except FileExistsError:
+            counter += 1
+            continue

The previous review's input validation suggestions are still valid and should be implemented alongside these changes.

🧹 Nitpick comments (2)
src/qubex/analysis/fitting.py (1)

260-359: Add input validation for polynomial degree.

While the implementation is solid, it should validate that the polynomial degree is non-negative and less than the number of data points to prevent potential fitting issues.

 def fit_polynomial(
     *,
     target: str,
     x: npt.NDArray[np.float64],
     y: npt.NDArray[np.float64],
     degree: int,
     plot: bool = True,
     title: str = "Polynomial fit",
     xaxis_title: str = "x",
     yaxis_title: str = "y",
     xaxis_type: Literal["linear", "log"] = "linear",
     yaxis_type: Literal["linear", "log"] = "linear",
 ) -> dict:
+    if degree < 0:
+        raise ValueError("Polynomial degree must be non-negative")
+    if degree >= len(x):
+        raise ValueError("Polynomial degree must be less than the number of data points")
src/qubex/analysis/visualization.py (1)

302-306: Consider parameterizing the image dimensions

While the save_image integration is good, the hardcoded width/height values should be parameterized for flexibility.

 def scatter_iq_data(
     data: Mapping[str, IQArray],
     *,
     save_image: bool = False,
+    image_width: int = 500,
+    image_height: int = 400,
     title: str = "I/Q plane",
     xlabel: str = "In-phase (arb. unit)",
     ylabel: str = "Quadrature (arb. unit)",
 ) -> None:
     # ... existing code ...
     if save_image:
         save_figure_image(
             fig,
             name="iq_data",
-            width=500,
-            height=400,
+            width=image_width,
+            height=image_height,
         )

Also applies to: 355-361

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe1c22 and 5efe197.

📒 Files selected for processing (2)
  • src/qubex/analysis/fitting.py (35 hunks)
  • src/qubex/analysis/visualization.py (10 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
src/qubex/analysis/fitting.py

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (9)
src/qubex/analysis/fitting.py (4)

214-238: LGTM! Well-documented implementation of the square root Lorentzian function.

The function is correctly implemented and includes comprehensive docstrings with clear parameter descriptions.


1695-1929: LGTM! Comprehensive implementation of 3D rotation fitting.

The implementation includes:

  • Correct mathematical formulation of rotation matrices
  • FFT-based parameter estimation
  • Comprehensive visualization with both 2D and 3D plots
  • Clear error handling and input validation

521-521: LGTM! Improved API consistency with dictionary returns.

The change from tuples/floats to dictionaries as return types is a good improvement because it:

  • Makes the API more consistent across all fitting functions
  • Makes the return values self-documenting
  • Allows for future extensibility without breaking changes

Also applies to: 538-539, 618-618, 649-650, 753-754, 784-785, 1472-1472, 1493-1494


615-615: LGTM! Consistent terminology in axis labels.

The change from "Amplitude (arb. units)" to "Signal (arb. unit)" makes the terminology more consistent and accurate across all plotting functions.

Also applies to: 750-750, 1246-1246, 1356-1356

src/qubex/analysis/visualization.py (5)

139-139: LGTM: Consistent terminology update

The ylabel change maintains consistency with other plotting functions in the module.


213-217: LGTM: Improved function signature and consistent terminology

Good improvements:

  • Making arguments keyword-only with * improves function call safety
  • ylabel change maintains consistency across the module

246-249: LGTM: Consistent improvements

The changes align with the module-wide improvements in function signatures and terminology.


376-377: LGTM: Enhanced visualization styling

Good improvements:

  • Consistent terminology in axis labels
  • Enhanced text styling with better visibility and readability

Also applies to: 412-425


168-175: LGTM: Improved function naming and flexibility

The renaming to plot_bloch_vectors better reflects the quantum mechanical context, and the new mode parameter adds useful visualization options.

Let's verify the impact of the function rename:

✅ Verification successful

Function rename has been properly propagated throughout the codebase

The search results show that:

  • No references to the old plot_state_vectors name exist in the codebase
  • The new plot_bloch_vectors function is:
    • Defined in src/qubex/analysis/visualization.py
    • Exported in src/qubex/analysis/__init__.py
    • Imported and used correctly in src/qubex/simulator/quantum_simulator.py and src/qubex/experiment/experiment.py

All references have been updated to use the new name, and there are no lingering references to the old function name that would cause issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any remaining references to the old function name
rg "plot_state_vectors" --type py

Length of output: 33


Script:

#!/bin/bash
# Let's search for both old and new function names to understand the usage
rg "plot_(state|bloch)_vectors" --type py -A 2

Length of output: 1463


Script:

#!/bin/bash
# Let's also check git history to see the changes
git log -p --no-merges -G "plot_state_vectors" -- "*.py"

Length of output: 0


Script:

#!/bin/bash
# Let's check for any test files that might use this function
fd "test.*\.py$" --exec grep -l "plot_.*vectors"

Length of output: 50


Script:

#!/bin/bash
# Let's check for any imports of this function
ast-grep --pattern 'from $_ import plot_state_vectors'

Length of output: 56


Script:

#!/bin/bash
# Check for any imports of the new function name
ast-grep --pattern 'from $_ import plot_bloch_vectors'

Length of output: 142

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/qubex/analysis/fitting.py (1)

260-359: Consider handling polynomial fitting edge cases
The function elegantly handles scenarios without real roots in range by returning np.nan. However, you might want to capture more detail about fitting failures, such as returning an error message in the dictionary instead of merely printing it, to maintain a consistent structured return for all outcomes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5efe197 and f40480c.

📒 Files selected for processing (1)
  • src/qubex/analysis/fitting.py (35 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
src/qubex/analysis/fitting.py

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (1)
src/qubex/analysis/fitting.py (1)

1687-1687: Fix mutable default argument
This closely matches a previous comment regarding using np.array as a default argument. The same array instance can be shared across calls, leading to unintended side effects.

-def fit_rotation(
-    times: npt.NDArray[np.float64],
-    data: npt.NDArray[np.float64],
-    r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
-    ...
+def fit_rotation(
+    times: npt.NDArray[np.float64],
+    data: npt.NDArray[np.float64],
+    r0: npt.NDArray[np.float64] | None = None,
+    ...
 ):
+    if r0 is None:
+        r0 = np.array([0, 0, 1])
🧰 Tools
🪛 Ruff (0.8.2)

1687-1687: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

@@ -322,7 +449,7 @@ def fit_rabi(
# )
except RuntimeError:
print(f"Failed to fit the data for {target}.")
return RabiParam(target, 0.0, 0.0, 0.0, 0.0, noise, angle)
return RabiParam(target, np.nan, np.nan, np.nan, np.nan, noise, angle)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Unify return type for consistent library API
While returning a RabiParam object is optimal for object-oriented usage, almost all other fitting functions return a dictionary. If you want to keep the library interface uniform, consider switching to a dictionary, or conversely migrate the other functions to return a data class.

-def fit_rabi(...) -> RabiParam:
+def fit_rabi(...) -> dict:
     ...
-    return RabiParam(
-        target=target,
-        amplitude=amplitude,
-        ...
-    )
+    return {
+        "target": target,
+        "amplitude": amplitude,
+        "frequency": frequency,
+        "phase": phase,
+        "offset": offset,
+        "noise": noise,
+        "angle": angle,
+    }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +214 to +238
def func_sqrt_lorentzian(
f: npt.NDArray[np.float64],
A: float,
f0: float,
Omega: float,
C: float,
) -> npt.NDArray[np.float64]:
"""
Calculate a square root Lorentzian function with given parameters.

Parameters
----------
f : npt.NDArray[np.float64]
Frequency points for the function evaluation.
A : float
Amplitude of the square root Lorentzian function.
f0 : float
Central frequency of the square root Lorentzian function.
Omega : float
Width of the square root Lorentzian function.
C : float
Vertical offset of the square root Lorentzian function.
"""
return A / np.sqrt(1 + ((f - f0) / Omega) ** 2) + C

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add parameter validation for Omega in sqrt-lorentzian function
The codebase shows that func_sqrt_lorentzian is used in curve fitting without explicit bounds or validation for Omega. While curve_fit can accept bounds, they aren't being set for the sqrt-lorentzian fit. To prevent potential domain issues, you should add a validation check for Omega > 0 in the function implementation.

  • In src/qubex/analysis/fitting.py, add parameter validation to func_sqrt_lorentzian:
def func_sqrt_lorentzian(f, A, f0, Omega, C):
    if Omega <= 0:
        raise ValueError("Omega must be positive")
    return A / np.sqrt(1 + ((f - f0) / Omega) ** 2) + C
🔗 Analysis chain

Confirm domain validity for sqrt-lorentzian
While the implementation looks correct, consider verifying that Omega > 0 to avoid potential domain issues (e.g., division by zero or taking the square root of negative values) if the input parameters or data differ from your assumptions.

You can run the following script to check whether func_sqrt_lorentzian is only called with valid, positive Omega parameters throughout the codebase:


Let me gather more information about the parameter bounds and validation.


Let me check one more thing to see if there are any parameter validations or bounds specifically for the sqrt-lorentzian fitting.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for usage of func_sqrt_lorentzian to see if there is any clamp or check for Omega
rg -A 10 "func_sqrt_lorentzian"

Length of output: 1789


Script:

#!/bin/bash
# Search for bounds definition and parameter validation
rg -B 5 -A 10 "bounds=" src/qubex/analysis/fitting.py

Length of output: 7083


Script:

#!/bin/bash
# Search for the sqrt lorentzian fit function implementation
rg -B 10 -A 20 "def fit_sqrt_lorentzian" src/qubex/analysis/fitting.py

Length of output: 864

…ndling; update data normalization in Experiment class
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/qubex/analysis/fitting.py (2)

260-359: Add error handling for polynomial fitting.

While the function handles root finding errors well, it should also handle potential errors from np.polyfit(). Consider wrapping the fitting in a try-except block:

-    popt = np.polyfit(x, y, degree)
-    fun = np.poly1d(popt)
-    y_fit = fun(x)
+    try:
+        popt = np.polyfit(x, y, degree)
+        fun = np.poly1d(popt)
+        y_fit = fun(x)
+    except (ValueError, np.linalg.LinAlgError) as e:
+        print(f"Failed to fit polynomial: {str(e)}")
+        return {
+            "popt": None,
+            "fun": None,
+            "root": None,
+            "fig": None,
+        }

1770-1780: Add validation for FFT-based parameter estimation.

The initial parameter estimation using FFT could fail if the input data is too short or contains no periodic signal.

Add validation:

     if p0 is None:
         N = len(times)
+        if N < 2:
+            raise ValueError("At least 2 data points required for parameter estimation")
         dt = times[1] - times[0]
+        if dt <= 0:
+            raise ValueError("Time steps must be positive")
         F = np.array(fft(data[:, 2]))
         f = np.array(fftfreq(N, dt)[1 : N // 2])
+        if len(f) == 0:
+            raise ValueError("Cannot estimate frequency from the given data")
         i = np.argmax(np.abs(F[1 : N // 2]))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f40480c and c3f88b7.

📒 Files selected for processing (2)
  • src/qubex/analysis/fitting.py (34 hunks)
  • src/qubex/experiment/experiment_result.py (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/qubex/experiment/experiment_result.py
🧰 Additional context used
🪛 Ruff (0.8.2)
src/qubex/analysis/fitting.py

1693-1693: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (4)
src/qubex/analysis/fitting.py (4)

214-238: Add parameter validation for Omega.

The function needs validation to ensure Omega > 0 to prevent domain errors when calculating the square root.


452-452: LGTM! Improved consistency and plot readability.

The changes enhance the function by:

  1. Making the return type consistent with other fitting functions
  2. Adding clear frequency annotation to the plot

Also applies to: 488-495


Line range hint 521-602: LGTM! Enhanced error reporting and visualization.

The changes improve the function by:

  1. Providing comprehensive error information in the return dictionary
  2. Adding clear annotations to the plot
  3. Maintaining consistency with other fitting functions

1869-1926: LGTM! Well-implemented 3D quantum state visualization.

The visualization is comprehensive and includes:

  1. Data points and fit line in 3D space
  2. Semi-transparent Bloch sphere
  3. Appropriate axis labels and scaling

Comment on lines +1690 to +1693
def fit_rotation(
times: npt.NDArray[np.float64],
data: npt.NDArray[np.float64],
r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix mutable default argument.

Using a mutable object (numpy array) as a default argument can lead to unexpected behavior since the same array object is shared between function calls.

Apply this fix:

-def fit_rotation(
-    times: npt.NDArray[np.float64],
-    data: npt.NDArray[np.float64],
-    r0: npt.NDArray[np.float64] = np.array([0, 0, 1]),
+def fit_rotation(
+    times: npt.NDArray[np.float64],
+    data: npt.NDArray[np.float64],
+    r0: npt.NDArray[np.float64] | None = None,

Then initialize the default value within the function:

    if r0 is None:
        r0 = np.array([0, 0, 1])
🧰 Tools
🪛 Ruff (0.8.2)

1693-1693: Do not perform function call np.array in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/qubex/pulse/pulse_schedule.py (5)

Line range hint 19-50: LGTM! Consider enhancing the docstring.

The new targets parameter implementation correctly handles both list and dictionary inputs, allowing for flexible target metadata storage.

Consider updating the docstring to include an example of dictionary-based initialization:

# Example with dictionary initialization
targets = {
    "Q01": {"frequency": 5.0, "object": "qubit1"},
    "Q02": {"frequency": 5.2, "object": "qubit2"}
}
ps = PulseSchedule(targets)

233-264: Enhance docstrings for transformation methods.

The new transformation methods are well-implemented but would benefit from more detailed documentation.

Add parameter descriptions and return type documentation:

def scaled(self, scale: float) -> PulseSchedule:
    """
    Returns a scaled pulse schedule.

    Parameters
    ----------
    scale : float
        The scaling factor to apply to all pulses.

    Returns
    -------
    PulseSchedule
        A new pulse schedule with scaled amplitudes.
    """

Line range hint 278-397: LGTM! Consider caching downsampled data.

The plot method improvements with downsampling and metadata annotations are well implemented. However, for frequently plotted schedules, consider caching the downsampled data.

def _get_downsampled_data(self, data: npt.NDArray, n_samples: int) -> npt.NDArray:
    """Cache and return downsampled data."""
    cache_key = (data.tobytes(), n_samples)
    if not hasattr(self, '_downsample_cache'):
        self._downsample_cache = {}
    if cache_key not in self._downsample_cache:
        self._downsample_cache[cache_key] = self._downsample(data, n_samples)
    return self._downsample_cache[cache_key]

497-505: Add return type hint to _downsample method.

The downsampling implementation is efficient but would benefit from complete type hints.

    @staticmethod
    def _downsample(
        data: npt.NDArray,
        n_max_points: int,
-    ) -> npt.NDArray:
+    ) -> npt.NDArray[np.float64]:

Line range hint 1-505: Consider implementing serialization for pulse schedules.

The PulseSchedule class has evolved into a robust implementation for quantum pulse control. Consider adding serialization capabilities to save and load pulse schedules, which would be valuable for experiment reproducibility.

Key aspects to consider:

  1. JSON serialization for metadata (targets, frequencies, objects)
  2. Efficient binary format for pulse data (e.g., HDF5)
  3. Version tracking for backward compatibility
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3f88b7 and 69c417d.

📒 Files selected for processing (1)
  • src/qubex/pulse/pulse_schedule.py (13 hunks)
🔇 Additional comments (3)
src/qubex/pulse/pulse_schedule.py (3)

55-90: LGTM! Well-structured property implementations.

The new properties provide clean access to target attributes with good encapsulation and clear documentation.


Line range hint 464-486: LGTM! Clean implementation of pulse range retrieval.

The method correctly uses the new labels property and maintains clear type hints.


Line range hint 141-192: Verify backward compatibility of barrier method changes.

The barrier method now defaults to using targets.keys() instead of the previous targets list. While the implementation is correct, this change might affect existing code.

✅ Verification successful

Let me analyze the barrier method usage in the codebase to verify backward compatibility.


No backward compatibility issues with barrier method changes

Based on the test cases and usage patterns found in the codebase:

  1. The barrier method is used in two ways:
    • Without arguments (barrier()): Used to synchronize all targets
    • With specific targets (barrier(["Q00", "Q01"])): Used to synchronize specific targets

Both these usage patterns are preserved in the new implementation:

  • When called without arguments, targets or list(self.targets.keys()) correctly defaults to all targets
  • When called with specific targets, the provided list is used directly

The change from using the targets list to targets.keys() maintains the same behavior because both approaches result in the same set of target labels being synchronized, as verified by the passing test cases test_barrier() and test_specific_barrier().

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing barrier method calls that might be affected
rg -A 2 "barrier\(" --type py

Length of output: 7864


Script:

#!/bin/bash
# Let's check the test file more closely to understand the behavior
cat tests/pulse/test_pulse_schedule.py

Length of output: 3698

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
tests/pulse/test_blank.py (2)

3-3: Consider removing or retaining the blank line based on team conventions.

This empty line can improve readability by visually separating imports from business logic. If your coding guidelines discourage isolated blank lines, feel free to remove it.


Line range hint 8-24: Strengthen array comparisons for pulse.values.

When verifying that pulse.values holds zeros, consider using np.array_equal(pulse.values, expected_array) or a specialized NumPy testing helper like np.testing.assert_array_equal for more reliable comparisons and clearer error messages.

tests/pulse/test_flat_top.py (1)

Line range hint 16-27: Comprehensive initialization test.

  • Testing with valid parameters and comparing pulse.values to a known expected list is ideal for confirming correct amplitude shaping.
  • Consider also asserting the pulse’s amplitude property or other derived attributes for an even broader coverage of correctness.
tests/pulse/test_gaussian.py (1)

21-22: Verifying parameter initialization and waveform calculation.

  • Checking specified parameters, including sigma and beta, is crucial for Gaussian waveform generation.
  • Approximating expected complex values confirms wave correctness.
tests/pulse/test_pulse.py (1)

Line range hint 47-62: Typo in function name and thorough zero-padding tests.

  1. There’s an extra “d” in test_paddded; please rename it to test_padded to maintain consistency.
  2. The zero-padding checks (left and right) are well-executed. Verifying the new values array is commendable.
-def test_paddded():
+def test_padded():
    """Pulse should be padded with zeros."""
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69c417d and e9ac9b4.

📒 Files selected for processing (10)
  • tests/pulse/test_blank.py (1 hunks)
  • tests/pulse/test_drag.py (1 hunks)
  • tests/pulse/test_flat_top.py (1 hunks)
  • tests/pulse/test_gauss.py (0 hunks)
  • tests/pulse/test_gaussian.py (2 hunks)
  • tests/pulse/test_phase_shift.py (1 hunks)
  • tests/pulse/test_pulse.py (1 hunks)
  • tests/pulse/test_pulse_sequence.py (1 hunks)
  • tests/pulse/test_raised_cosine.py (2 hunks)
  • tests/pulse/test_rect.py (1 hunks)
💤 Files with no reviewable changes (1)
  • tests/pulse/test_gauss.py
✅ Files skipped from review due to trivial changes (1)
  • tests/pulse/test_pulse_sequence.py
🔇 Additional comments (29)
tests/pulse/test_phase_shift.py (1)

3-3: Good addition of PhaseShift, Pulse, and PulseSequence imports.

The explicit import of these classes increases test clarity and ensures that the PhaseShift class is being properly utilized in the suite.

tests/pulse/test_drag.py (2)

3-3: New import statements look good.

Importing Drag and Pulse together is appropriate and clarifies the relationship between the two classes for testing.


Line range hint 30-36: Excellent edge case coverage with zero duration testing.

Including the test_zero_duration method to validate that an empty array of complex128 values is generated helps ensure robust coverage for corner cases.

tests/pulse/test_rect.py (1)

3-3: Accurate import for Rect class.

This aligns with the updated pulse architecture, and the class is properly tested below.

tests/pulse/test_raised_cosine.py (5)

4-4: Import statement updated to reference RaisedCosine correctly.

Replacing any old references (e.g., DragCos) with the new RaisedCosine class ensures tests remain in sync with code changes.


10-11: Clear inheritance test for RaisedCosine.

Testing that RaisedCosine is indeed a subclass of Pulse verifies the class hierarchy.


15-17: Appropriate error handling for missing duration parameter.

Raising a TypeError for missing arguments is consistent with Python’s built-in behavior, ensuring clarity for developers.


21-22: Comprehensive initialization test.

Validating RaisedCosine(duration=5 * dt, amplitude=1, beta=1) ensures correct parameter handling and value generation.


36-37: Zero duration coverage is thorough.

Ensuring that a RaisedCosine pulse with zero duration yields an empty array extends test robustness for edge cases.

tests/pulse/test_flat_top.py (5)

3-3: No issues with the new import spacing.
The blank line helps to visually separate third-party imports from internal module imports, improving readability.


Line range hint 7-10: Test case naming is descriptive and purposeful.
The test_inheritance function clearly focuses on verifying class hierarchy, ensuring FlatTop inherits from Pulse. Good coverage for confirming inheritance relationships.


Line range hint 12-14: Proper exception testing.
The test_empty_init function appropriately checks that calling FlatTop() without required initialization parameters raises a TypeError. This helps to maintain robust parameter validation.


Line range hint 29-34: Zero-duration edge case handled gracefully.
Having a test that ensures FlatTop returns an empty array with zero duration is a good approach to confirm there's no unexpected behavior in boundary conditions.


Line range hint 36-41: Proper error handling for invalid duration.

  • Verifying that a ValueError is raised when duration <= 2 * tau ensures mathematical integrity of the pulse waveform.
  • The clear error message enhances transparency for any caller misconfigurations.
tests/pulse/test_gaussian.py (5)

3-4: Sensible import for new Gaussian class.
The updated import statement for Gaussian aligns with the recent refactoring. This is consistent with the project’s pulse module structure.


10-11: Accurate test for inheritance.
The test_inheritance function confirms that Gaussian inherits from Pulse, helping ensure expected hierarchy is maintained.


15-17: Correct exception test for missing arguments.
Raising a TypeError when duration is not specified fulfills Python’s constructor argument requirements and prevents silent misconfigurations.


36-37: Solid coverage for edge-case with zero duration.
Ensuring Gaussian results in an empty array for zero duration helps confirm no unexpected math or indexing errors occur in boundary conditions.


43-45: Ensuring invalid parameter raises the correct error.
A ValueError when sigma=0 is vital to avoid division or exponential anomalies in Gaussian amplitude computations.

tests/pulse/test_pulse.py (10)

3-3: No issues with the new import and sampling period usage.
The addition of Waveform and the recognition of Pulse.SAMPLING_PERIOD is appropriate for testing.


Line range hint 7-10: Inheritance test looks solid.
The test correctly asserts that Pulse is a subclass of Waveform.


Line range hint 13-16: Good negative test coverage for Pulse initialization.
You correctly ensure a TypeError is raised when no parameters are provided, preventing unintended usage.


Line range hint 19-23: Validation of empty list initialization.
This test confirms behavioral correctness for edge cases (no values). All assertions are relevant.


Line range hint 26-36: Comprehensive check on real, imaginary, and complex values.
Excellent coverage ensuring that Pulse([0, -0.5, +0.5j]) sets all derived attributes (real, imag, abs, angle) correctly.


Line range hint 39-44: Copy method testing is concise.
The test verifies that copy produces a distinct instance with identical values, adhering to expected immutable semantics.


Line range hint 65-69: Scaling test is straightforward and effective.
The approach of verifying scaled values via pytest.approx is appropriate and ensures relative floating-point accuracy.


Line range hint 72-84: Proper detuning validation.
Applying a complex exponential shift for each time step is correct. Testing intermediate steps with pytest.approx ensures numerical stability.


Line range hint 87-93: Phase-shifting test covers negative real/imag transitions.
The test ensures each value is phase-shifted correctly and remains distinct from the original Pulse.


Line range hint 96-101: Repetition logic verified.
Repeating the pulse multiple times is effectively tested, confirming that the updated values array meets expectations.

@amachino amachino merged commit aa25d69 into main Dec 31, 2024
3 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (2)
README.md (2)

Line range hint 6-9: Review the pip version requirement.

The requirement for pip 24.0 seems incorrect as this version hasn't been released yet. Consider:

  • Specifying a minimum pip version instead (e.g., "pip >= 21.0")
  • Or removing the specific pip version requirement if it's not strictly necessary

Line range hint 1-39: Add version information and highlight new features.

Since this is part of the v1.2.0 release:

  • Consider adding a version badge or current version number
  • Include a "What's New" or "Changelog" section highlighting the key features mentioned in the PR (quantum simulation improvements, experiment management enhancements, etc.)
🧹 Nitpick comments (2)
README.md (2)

1-4: Consider enhancing the introduction with more specific details.

The introduction provides a good overview but could be more helpful to users by:

  • Listing specific supported quantum hardware platforms
  • Adding links to documentation for key features (T1/T2 experiments, gate calibration, etc.)
  • Including a brief code example demonstrating basic usage

36-39: Enhance the usage section with more details.

Consider improving the usage section by:

  • Adding a quick-start example
  • Providing a brief description of each example in the examples folder
  • Including links to specific example notebooks mentioned in the AI summary (e.g., 0_basic_usage.ipynb, 1_frequency_inspection.ipynb)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9ac9b4 and cbcad89.

📒 Files selected for processing (2)
  • README.md (2 hunks)
  • pyproject.toml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml

Comment on lines +20 to 24
### qubex with backend (only for Linux)

```bash
pip install "qubex[backend] @ git+https://github.com/amachino/qubex.git"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify backend installation requirements and features.

The backend installation section would benefit from:

  • Explaining what additional features the backend provides
  • Listing specific Linux dependencies or requirements
  • Clarifying why it's Linux-only

Comment on lines +28 to +31
```bash
git clone git+https://github.com/amachino/qubex.git
cd qubex
pip install -e .
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the git clone command syntax.

The git clone command contains an incorrect URL format.

Apply this correction:

-git clone git+https://github.com/amachino/qubex.git
+git clone https://github.com/amachino/qubex.git

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants