### Install QoolQit from Source with Development Dependencies Source: https://github.com/pasqal-io/qoolqit/blob/main/README.md Set up a development environment and install QoolQit from source using venv and pip, including development dependencies. ```sh python -m venv .venv source .venv/bin/activate pip install -e .[dev] ``` -------------------------------- ### Install and Use Pre-commit Hooks Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/CONTRIBUTING.md Install pre-commit, set up the hooks for the repository, and run them on all files to ensure code quality before committing. ```shell pip install pre-commit pre-commit install pre-commit run --all-files ``` -------------------------------- ### Install QoolQit from PyPI Source: https://github.com/pasqal-io/qoolqit/blob/main/README.md Use this command to install the QoolQit library using pip. ```sh pip install qoolqit ``` -------------------------------- ### Initialize PasqalCloud Connection Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Set up a connection to the Pasqal Cloud services. This example shows the structure for providing credentials, though actual credentials are not included. ```python from pulser_pasqal import PasqalCloud # connection = PasqalCloud( # username=USERNAME, # Your username or email address for the Pasqal Cloud Platform # password=PASSWORD, # The password for your Pasqal Cloud Platform account # project_id=PROJECT_ID, # The ID of the project associated to your account # ) ``` -------------------------------- ### Clone QoolQit GitHub Repository Source: https://github.com/pasqal-io/qoolqit/blob/main/README.md Clone the QoolQit repository from GitHub to install from source. ```sh git clone https://github.com/pasqal-io/qoolqit.git ``` -------------------------------- ### Retrieve Results from Emulator Job Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Access and query the results from an emulator job, including getting all result tags and specific observable values at a given time. ```python # get the results results = job.results() # get the result tags (this will include the observable names) print(results.get_result_tags()) # get the result for the occupation observable at time 1.0 (final time) results.get_result("occupation", time=1.0) ``` -------------------------------- ### Define Custom GraphToGraphEmbedder Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/extended_usage/custom_embedders.ipynb Define a custom embedder by providing an embedding function and a configuration dataclass. This example shows how to create a `GraphToGraphEmbedder` with a custom function and config. ```python from dataclasses import dataclass from qoolqit import DataGraph from qoolqit.embedding import EmbedderConfig, GraphToGraphEmbedder def my_embedding_function(graph: DataGraph, param1: float) -> DataGraph: """Some embedding function that manipulates the input graph. This docstring should be clear on the embedding logic, because it will be directly accessed by the embedder.info property. Arguments: param1: a useless parameter... """ return graph @dataclass class MyEmbedderConfig(EmbedderConfig): param1: float = 1.0 embedder = GraphToGraphEmbedder(my_embedding_function, MyEmbedderConfig()) print(embedder) ``` -------------------------------- ### Initializing QoolQit Devices Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Demonstrates how to initialize different types of QoolQit devices: a mock device for unconstrained prototyping, a realistic analog device, and a digital-analog device. ```python from qoolqit import AnalogDevice, DigitalAnalogDevice, MockDevice # An example of a mock device with no hardware constraints device_ideal = MockDevice() # An example of a real device device_real = AnalogDevice() # An example of a real device with digital-analog capabilities. device_real_digital = DigitalAnalogDevice() ``` -------------------------------- ### Get Job Identifiers Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Retrieve the unique batch and job identifiers for a submitted job. These IDs are used for tracking and retrieving specific jobs. ```python from qoolqit.execution import get_batch_id # Get the unique batch identifier for the job batch_id = get_batch_id(job) # Get the unique job identifier job_id = job.job_id() # For remote jobs, retrieve a job using its ID from qoolqit.execution import retrieve_remote_job retrieved_job = retrieve_remote_job(connection, job_id, batch_id=batch_id) ``` -------------------------------- ### Configure Emulation and Run Blockade/Non-Blockade Programs Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Sets up emulation configuration to sample bitstrings and runs both the blockade and non-blockade quantum programs, asserting their completion. ```python # Configure emulation: sample bitstrings at 81 evaluation times eval_times = np.linspace(0.0, 1.0, 81) bitstrings = BitStrings(evaluation_times=list(eval_times), num_shots=1000) configuration = EmulationConfig(observables=[bitstrings]) emulator = LocalEmulator(emulation_config=configuration) job_blockade = emulator.run(program_blockade) assert job_blockade.get_status() == JobStatus.DONE result_blockade = job_blockade.results() job_no_blockade = emulator.run(program_no_blockade) assert job_no_blockade.get_status() == JobStatus.DONE result_no_blockade = job_no_blockade.results() ``` -------------------------------- ### Access Minimum Register Distance Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Get the smallest distance between any two qubits in the Register. This can be a key parameter in quantum gate design and error analysis. ```python register.min_distance() ``` -------------------------------- ### Get Minimum and Maximum Distances Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Calculate the minimum and maximum distances between nodes in the graph. Options are available to consider only connected nodes or disconnected nodes. ```python # Compute for all node pairs graph.min_distance() graph.max_distance() # Compute only for connected nodes graph.min_distance(connected = True) # Compute only for disconnected nodes graph.min_distance(connected = False) ``` -------------------------------- ### Set Up Development Environment with Hatch Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/CONTRIBUTING.md Use Hatch to automatically create and enter a development environment with all necessary dependencies. ```shell hatch shell ``` -------------------------------- ### Get Sorted Edges Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Access the sorted edges of the graph, where each edge tuple (u, v) satisfies u < v. This ensures consistent ordering. ```python graph.sorted_edges ``` -------------------------------- ### Initialize QPU Backend Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Initialize a QPU backend for executing programs. This backend is configured with the connection and the number of shots. ```python from qoolqit.execution import QPU qpu = QPU(connection=connection, num_shots=500) ``` -------------------------------- ### Initialize Local Emulator with QutipBackendV2 Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Initializes a LocalEmulator specifying the QutipBackendV2 as the backend type. This backend is suitable for programs up to ~12 qubits. ```python from qoolqit.execution import BackendType, LocalEmulator emulator = LocalEmulator(backend_type=BackendType.QutipBackendV2) ``` -------------------------------- ### Execute Quantum Program on Local Emulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Instantiates a LocalEmulator and runs the compiled quantum program on it to simulate execution and obtain results. ```python from qoolqit.execution import LocalEmulator # instantiate a local emulator emulator = LocalEmulator() # execute the program on the local emulator job = emulator.run(program) # get the results results = job.results() counter = results.final_bitstrings print(counter) ``` -------------------------------- ### Get All Node Pairs Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Retrieve all unique pairs of nodes in the graph, with each pair (u, v) satisfying u < v. This is useful for iterating over all possible connections. ```python graph.all_node_pairs ``` -------------------------------- ### Select and Connect to Pasqal Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Fetches specifications for the 'FRESNEL' Pasqal quantum device using PasqalCloud and establishes a connection. ```python from pulser_pasqal import PasqalCloud from qoolqit import Device fresnel_device = Device.from_connection(connection=PasqalCloud(), name="FRESNEL") ``` -------------------------------- ### Initialize Remote Emulator with Custom Configuration Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Initialize a remote emulator with a specific backend type, custom emulation configuration including observables and hardware modulation, and a defined number of shots. ```python from qoolqit.execution import ( BackendType, EmulationConfig, Occupation, RemoteEmulator, ) # define the observables to be evaluated at the specified times observables = (Occupation(evaluation_times=[0.5, 1.0]),) # emulation configuration to add observables and include hardware modulation emulation_config = EmulationConfig(observables=observables, with_modulation=True) # initialize the remote emulator with the custom configuration and num_shots remote_emulator = RemoteEmulator( backend_type=BackendType.EmuFreeBackendV2, connection=connection, emulation_config=emulation_config, num_shots=1000, ) ``` -------------------------------- ### Compose Waveforms with >> Operator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Combines multiple waveforms sequentially using the '>>' operator to create a composite waveform. The start and end times for each sub-waveform are automatically calculated. ```python wf_comp = wf1 >> wf2 >> wf3 ``` -------------------------------- ### Create Graph from Coordinates and Unit Disk Edges Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Initializes a graph from a list of coordinates and then adds edges based on a unit disk radius. Asserts the initial state of edges and the state after adding them. ```python from qoolqit import DataGraph coords = [(-1.0, 0.0), (0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.0, -1.0)] graph = DataGraph.from_coordinates(coords) assert len(graph.edges) == 0 graph.set_ud_edges(radius = 1.0) assert len(graph.edges) > 0 graph.draw() ``` -------------------------------- ### Initialize Remote Emulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Initialize a remote emulator using a Pasqal Cloud connection. This is the first step to running programs on remote emulation environments. ```python from qoolqit.execution import RemoteEmulator remote_emulator = RemoteEmulator(connection=connection) ``` -------------------------------- ### Define a Smooth Bell-Shaped Pulse Waveform Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/extended_usage/custom_waveforms.ipynb Implement a smooth, bell-shaped pulse using a sine-squared function. This waveform starts and ends at zero and reaches its maximum smoothly. It's recommended to override `max` and `min` for analytical bounds. ```python import math from qoolqit.waveforms import Waveform class SmoothPulse(Waveform): """Smooth bell-shaped pulse: Ω_max · sin²((π/2)·sin(πt/T)).""" def __init__(self, duration: float, omega_max: float) -> None: super().__init__(duration, omega_max=omega_max) def function(self, t: float) -> float: return self.omega_max * math.sin(0.5 * math.pi * math.sin(math.pi * t / self.duration)) ** 2 def max(self) -> float: # analytic maximum is always omega_max return self.omega_max def min(self) -> float: # starts and ends at zero return 0.0 ``` ```python pulse = SmoothPulse(2 * math.pi, omega_max=1.0) print(pulse) pulse.draw() ``` -------------------------------- ### Compile Quantum Program to Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Compiles the quantum program to be compatible with the selected device, preparing it for execution. ```python program.compile_to(device=fresnel_device) ``` -------------------------------- ### Defining Quantum Program Components for Compilation Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Sets up the necessary components for compiling a quantum program: defining drive waveforms, creating a register with specified qubit coordinates, and instantiating a quantum program with a target device. ```python from qoolqit import AnalogDevice, Drive, PiecewiseLinear, QuantumProgram, Register # Defining the Drive wf0 = PiecewiseLinear([1.0, 2.0, 1.0], [0.0, 0.5, 0.5, 0.0]) wf1 = PiecewiseLinear([1.0, 2.0, 1.0], [-1.0, -1.0, 1.0, 1.0]) drive = Drive(amplitude = wf0, detuning = wf1) # Defining the Register coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)] register = Register.from_coordinates(coords) # Creating the Program program = QuantumProgram(register, drive) device = AnalogDevice() ``` -------------------------------- ### Compile Program to Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Compiles a quantum program to a specified device and prints the compiled program details. Use this to see the device-specific representation of your program. ```python program.compile_to(device) print(program) ``` -------------------------------- ### Define and Compile a Quantum Program Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Defines a quantum program with registers, drives, and parameters, then compiles it for an AnalogDevice. This is a prerequisite for execution. ```python from qoolqit import AnalogDevice, Constant, Drive, QuantumProgram, Ramp, Register # Create the register register = Register.from_coordinates([(0,1), (0,-1), (2,0)]) # Defining the drive parameters omega = 0.8 delta_i = -2.0 * omega delta_f = -delta_i T = 25.0 # Defining the drive wf_amp = Constant(T, omega) wf_det = Ramp(T, delta_i, delta_f) drive = Drive(amplitude = wf_amp, detuning = wf_det) # Creating the program program = QuantumProgram(register, drive) # Compiling the program to a device program.compile_to(device=AnalogDevice()) ``` -------------------------------- ### Listing Available Default Devices Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Retrieves and displays a list of all available default quantum devices in QoolQit, along with their hardware specifications. ```python from qoolqit import available_default_devices available_default_devices() ``` -------------------------------- ### Draw Original and Compiled Programs Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Visualizes both the original quantum program and its compiled version. Use `compiled=True` to view the hardware-specific sequence. ```python program.draw() program.draw(compiled = True) ``` -------------------------------- ### Create QuantumProgram Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Pair a defined register (layout and interactions) with a drive (time-dependent controls) to create a QuantumProgram. The initial state is always |0>. ```python from qoolqit import QuantumProgram program = QuantumProgram( register=register, drive=drive ) ``` -------------------------------- ### Compile QuantumProgram to Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Translate an abstract QuantumProgram into a device-executable format using the compile_to method. This applies device-specific constraints and hardware limits. ```python from qoolqit import AnalogDevice device = AnalogDevice() program.compile_to(device) ``` -------------------------------- ### Run a Quantum Program on Local Emulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Executes a compiled quantum program using the LocalEmulator and retrieves the job handler. This is the basic method for local execution. ```python from qoolqit.execution import LocalEmulator emulator = LocalEmulator() job = emulator.run(program) results = job.results() ``` -------------------------------- ### Creating a QoolQit Device from a Pulser Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Demonstrates how to create a custom QoolQit device by modifying an existing Pulser device's specifications, such as max radial distance and sequence duration. ```python from dataclasses import replace from pulser import AnalogDevice as PulserAnalogDevice from qoolqit import Device # Converting the pulser Device object into a VirtualDevice object VirtualAnalog = PulserAnalogDevice.to_virtual() # Replacing desired values ModdedAnalogDevice = replace(VirtualAnalog, max_radial_distance=100, max_sequence_duration=7000) # Wrap a Pulser device object into a QoolQit Device mod_analog_device = Device(pulser_device=ModdedAnalogDevice) print(mod_analog_device) ``` -------------------------------- ### Define Annealing Parameters Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Sets up parameters for the annealing process, including median positive values from a matrix Q, and initial and final detuning values. ```python omega = np.median(Q[Q > 0]) delta_i = -1.0 delta_f = -np.diag(Q)[0] ``` -------------------------------- ### Fetch Available QPU Devices Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Fetch and display a list of available QPU devices from the Pasqal Cloud connection. This helps in selecting a target device for execution. ```python connection.fetch_available_devices() ``` -------------------------------- ### Fetching a QoolQit Device from a Pasqal Cloud Connection Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Shows how to fetch a QoolQit device named 'FRESNEL' from a Pasqal Cloud connection, useful for interacting with remote QPUs. ```python from pulser_pasqal import PasqalCloud from qoolqit import Device connection = PasqalCloud() print(connection.fetch_available_devices()) # fetch QoolQit device fresnel_device = Device.from_connection(connection=connection, name="FRESNEL") print(fresnel_device) ``` -------------------------------- ### Create Registers from Embedded Graphs Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Instantiates QoolQit Registers from the embedded graphs, preparing them for further quantum computations or simulations. The registers are then visualized. ```python from qoolqit import Register register_1 = Register.from_graph(embedded_graph_1) register_2 = Register.from_graph(embedded_graph_2) register_1.draw() register_2.draw() ``` -------------------------------- ### Configure Local Emulator with Observables and Modulation Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Instantiate a LocalEmulator with a custom EmulationConfig that specifies observables (Occupation and BitStrings) and enables hardware modulation. ```python from qoolqit.execution import BitStrings, EmulationConfig, LocalEmulator, Occupation # observables to compute, occupation of the Rydberg state and bitstrings sample observables = (Occupation(evaluation_times=[0.1, 0.5, 1.0]), BitStrings(num_shots=100)) emulation_config = EmulationConfig( observables=observables, with_modulation=True ) # emulator with a custom configuration emulator = LocalEmulator(emulation_config=emulation_config) # run the program with the new config job = emulator.run(program) ``` -------------------------------- ### Compile Quantum Programs for Analog Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Compiles two quantum programs, one for the blockade regime and one for the non-blockade regime, targeting a generic analog device. ```python # Build and compile programs program_blockade = QuantumProgram(register, drive_blockade) program_no_blockade = QuantumProgram(register, drive_no_blockade) device = AnalogDevice() program_blockade.compile_to(device) program_no_blockade.compile_to(device) ``` -------------------------------- ### Initialize and Use InteractionEmbedder Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Initialize an `InteractionEmbedder` with a configuration, access its information and configuration, and then use it to embed data. Ensure `InteractionEmbedder` and `InteractionEmbedderConfig` are imported. ```python from qoolqit import InteractionEmbedder, InteractionEmbedderConfig # Initialize the embedder config = InteractionEmbedderConfig() embedder = InteractionEmbedder(config=config) # Access information about the embedding algorithm embedder.info # Access the configuration of the embedding algorithm embedder.config # Embed the data with the embedder embedded_data = embedder.embed(data) ``` -------------------------------- ### Compile Program to Device with Max Duration Ratio Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/device_and_compilation.ipynb Compiles a quantum program to a device, scaling the total duration to the maximum allowed by the hardware. This is useful for adiabatic protocols where time is a primary variable. ```python # Compilation to AnalogDevice max duration program.compile_to(device, device_max_duration_ratio=1.0) program.draw(compiled = True) ``` -------------------------------- ### Visualize Compiled Quantum Program Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Draws the compiled quantum program sequence, showing the representation that will be used by emulators or realized on a quantum device. ```python program.draw(compiled=True) ``` -------------------------------- ### Define Quantum Program with Register and Drive Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Construct a QuantumProgram by combining a Register, defined by qubit coordinates, and a Drive, which includes amplitude and detuning waveforms. The program is initially uncompiled. ```python from qoolqit import Drive, PiecewiseLinear, QuantumProgram, Register # Defining the Drive wf0 = PiecewiseLinear([1.0, 2.0, 1.0], [0.0, 0.5, 0.5, 0.0]) wf1 = PiecewiseLinear([1.0, 2.0, 1.0], [-1.0, -1.0, 1.0, 1.0]) drive = Drive(amplitude = wf0, detuning = wf1) # Defining the Register coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)] register = Register.from_coordinates(coords) # Creating the Program program = QuantumProgram(register, drive) print(program) ``` -------------------------------- ### Run Compiled Program on Emulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Executes a compiled quantum program using a local emulator and retrieves the job status and results. ```python from qoolqit.execution import JobStatus, LocalEmulator emulator = LocalEmulator() job = emulator.run(program) assert job.get_status() == JobStatus.DONE results = job.results() ``` -------------------------------- ### Define Quantum Program Drive Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Constructs the drive for the quantum program using PiecewiseLinear for amplitude and Ramp for detuning, defining the annealing schedule. ```python from qoolqit import Drive, PiecewiseLinear, QuantumProgram, Ramp, Register # Defining the annealing schedule T = 40 wf_amp = PiecewiseLinear([T / 4, T / 2, T / 4], [0.0, omega, omega, 0.0]) det_wf = Ramp(T, delta_i, delta_f) drive = Drive(amplitude=wf_amp, detuning=det_wf) # Writing the quantum program program = QuantumProgram(register, drive) program.draw() ``` -------------------------------- ### Create Register from Coordinates Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Define qubit positions using a list of (x, y) coordinates. Use unit spacing for normalized interaction strengths. ```python from qoolqit import Register # Create a register from coordinates (dimensionless units) register = Register.from_coordinates([ (0, 0), (1, 0), (0.5, 0.866) ]) ``` -------------------------------- ### Initialize Interaction Embedder Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Initializes the InteractionEmbedder, a tool used to map a QUBO matrix to a graph representation suitable for embedding into a Rydberg analog model. ```python from qoolqit.embedding import InteractionEmbedder embedder = InteractionEmbedder() embedded_graph = embedder.embed(Q) ``` -------------------------------- ### Create a Line Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Generates a line graph with a specified number of nodes and spacing between them. Includes a call to draw the graph. ```python graph = DataGraph.line(n = 10, spacing = 1.0) graph.draw() ``` -------------------------------- ### Create a Random Unit-Disk Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Generates a random unit-disk graph by sampling points uniformly within a square area. Includes parameters for the number of nodes, radius, and area side length, and a call to draw the graph. ```python graph = DataGraph.random_ud(n = 10, radius = 1.0, L = 2.0) graph.draw() ``` -------------------------------- ### Add QoolQit as a Project Dependency Source: https://github.com/pasqal-io/qoolqit/blob/main/README.md Include QoolQit in your project's dependencies by adding it to the pyproject.toml file. ```toml [project] dependencies = [ "qoolqit" ] ``` -------------------------------- ### Construct DataGraph from Edges Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Instantiate a DataGraph by providing a list of edges. This is the default way to create a graph. ```python from qoolqit import DataGraph edges = [(0, 1), (1, 2), (2, 3), (3, 0)] graph = DataGraph(edges) ``` -------------------------------- ### Create a Square Lattice Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Constructs a square lattice graph with specified rows, columns, and spacing. Includes a call to draw the graph. ```python graph = DataGraph.square(m = 2, n = 2, spacing = 1.0) graph.draw() ``` -------------------------------- ### Compile Program for QPU Device Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Compile a program specifically for a target QPU device. This step is necessary before submitting a program to a QPU. ```python from qoolqit.devices import Device device = Device.from_connection(connection, "FRESNEL") program.compile_to(device=device) ``` -------------------------------- ### Initialize SpringLayoutEmbedder Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Initializes the SpringLayoutEmbedder with default parameters. This embedder wraps the nx.spring_layout function. ```python from qoolqit.embedding import SpringLayoutEmbedder embedder = SpringLayoutEmbedder() print(embedder) ``` -------------------------------- ### Helper Function to Create Quantum Program Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/error_handling.ipynb A utility function to create a QuantumProgram with configurable lattice size, amplitude, and detuning. Useful for testing different compilation scenarios. ```python # Or use built-in graph patterns from qoolqit import DataGraph, Drive, QuantumProgram, Register from qoolqit.waveforms import Interpolated, Ramp def create_program(L,amp,det): graph = DataGraph.square(m=L, n=L) register = Register.from_graph(graph) # LxL square lattice omega_wf = Interpolated(duration=50, values=[0, amp, 0]) delta_wf = Ramp(duration=50, initial_value=-det, final_value=det) drive = Drive(amplitude=omega_wf, detuning=delta_wf) return QuantumProgram(register=register,drive=drive) ``` -------------------------------- ### Define Quantum Program Components Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/error_handling.ipynb Defines the DataGraph, Register, and Drive objects for a quantum program. This is a foundational step before compilation. ```python from qoolqit import DataGraph, Register graph = DataGraph.square(m=2, n=2) register = Register.from_graph(graph) # 2x2 square lattice graph.draw() ``` ```python from qoolqit import Drive from qoolqit.waveforms import Interpolated, Ramp # Interpolated waveform: smooth curve through specified values omega_wf = Interpolated(duration=50, values=[0, 1, 0]) # Ramp waveform delta_wf = Ramp(duration=50, initial_value=-2, final_value=2) # Combine into a Drivejupyter kernelspec list drive = Drive( amplitude=omega_wf, detuning=delta_wf ) drive.draw() ``` ```python from qoolqit import AnalogDevice, QuantumProgram program = QuantumProgram( register=register, drive=drive ) device=AnalogDevice() program.compile_to(device) ``` ```python program.draw() program.compiled_sequence.draw() ``` -------------------------------- ### Create a Circle Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Constructs a circle graph with a specified number of nodes, spacing, and center coordinates. Includes a call to draw the graph. ```python graph = DataGraph.circle(n = 10, spacing = 1.0, center = (0.0, 0.0)) graph.draw() ``` -------------------------------- ### Compile Program with Device Max Duration Ratio Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Compiles a program to a device, rescaling the drive duration to a fraction of the device's maximum allowed duration. Useful for adiabatic protocols. ```python program.compile_to(device=fresnel_device, device_max_duration_ratio=1) program.compiled_sequence.draw() ``` -------------------------------- ### Create a Triangular Lattice Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Generates a triangular lattice graph with specified rows, columns, and spacing. Includes a call to draw the graph. ```python graph = DataGraph.triangular(m = 2, n = 2, spacing = 1.0) graph.draw() ``` -------------------------------- ### Create Register from Dictionary and List of Coordinates Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Instantiate a Register object using either a dictionary mapping qubit IDs to coordinates or a list of coordinates. The Register defines the qubit layout for a quantum program. ```python from qoolqit import Register # Instantiate a Register from a dictionary of coordinates. qubits = { 0: (-0.5, -0.5), 1: (-0.5, 0.5), 2: (0.5, -0.5), 3: (0.5, 0.5), } register = Register(qubits) # Instantiate a Register from a list of coordinates. coords = [(-0.5, -0.5), (-0.5, 0.5), (0.5, -0.5), (0.5, 0.5)] register = Register.from_coordinates(coords) print(register) register.draw() ``` -------------------------------- ### Display InteractionEmbedder Info Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Print the information about the InteractionEmbedder, including the algorithm and configuration details. This helps in understanding the available parameters for customization. ```python print(embedder.info) ``` -------------------------------- ### Create and Evaluate Base Waveforms Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Instantiate and evaluate basic waveforms like Delay, Constant, and Ramp. These form the building blocks for defining time-dependent control pulses in the drive Hamiltonian. ```python from qoolqit import Constant, Delay, Ramp # An empty waveform wf1 = Delay(1.0) print(wf1) # A waveform with a constant value wf2 = Constant(1.0, 2.0) print(wf2) # A waveform that ramps linearly between two values wf3 = Ramp(1.0, -1.0, 1.0) print(wf3) ``` ```python wf1(t = 0.0) wf2(t = 0.5) wf3(t = 1.0) print("wf1(t = 0.0) =", wf1(t = 0.0)) print("wf2(t = 0.5) =", wf2(t = 0.5)) print("wf3(t = 1.0) =", wf3(t = 1.0)) ``` -------------------------------- ### Create a New Git Branch Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/CONTRIBUTING.md Create a new branch for your contributions. Replace placeholders with your initials and a descriptive branch name. ```shell git branch / ``` -------------------------------- ### Define Quantum Register and Drives for Blockade Experiment Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Sets up a two-qubit register and defines two distinct drive configurations to demonstrate the Rydberg blockade regime and the non-blockade regime. ```python import numpy as np from qoolqit import Drive, QuantumProgram, Register from qoolqit.devices import AnalogDevice from qoolqit.execution import BitStrings, EmulationConfig, LocalEmulator from qoolqit.waveforms import Constant # Two qubits at unit distance => maximum interaction J = 1 register = Register.from_coordinates([(0, 0), (1, 0)]) duration = 10 # Blockade regime: Omega << J => double excitation is suppressed drive_blockade = Drive( amplitude=Constant(duration, 0.3), # Omega = 0.3 << 1 detuning=Constant(duration, 0.0) ) # Non-blockade regime: Omega >> J => drive dominates, both atoms can be excited drive_no_blockade = Drive( amplitude=Constant(duration, 2.0), # Omega = 2.0 >> 1 detuning=Constant(duration, 0.0) ) ``` -------------------------------- ### Submit Program to Remote Emulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/execution/execution.ipynb Submit a program to a remote emulator. The run() method returns a job handler for monitoring and retrieving results. ```python job = remote_emulator.run(program) ``` -------------------------------- ### Create a Heavy-Hexagonal Lattice Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Constructs a heavy-hexagonal lattice graph with specified rows, columns, and spacing. Includes a call to draw the graph. ```python graph = DataGraph.heavy_hexagonal(m = 2, n = 2, spacing = 1.0) graph.draw() ``` -------------------------------- ### Draw Graph with Coordinates Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Draw the graph, automatically utilizing the set node coordinates for positioning. This is useful for visualizing the physical layout of qubits. ```python graph.draw() ``` -------------------------------- ### Create Register from DataGraph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Generate a register layout from built-in DataGraph patterns like a square lattice. The register.draw() method visualizes the qubit positions. ```python from qoolqit import DataGraph graph = DataGraph.square(m=2, n=2) register = Register.from_graph(graph) # 2x2 square lattice register.draw() ``` -------------------------------- ### Create Drive with Waveforms Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/get_started/programming_with_qoolqit.ipynb Combine different waveform types (Interpolated, Constant, Ramp) to define the amplitude and detuning controls for a quantum drive. The drive.draw() method visualizes these waveforms. ```python from qoolqit import Drive from qoolqit.waveforms import Constant, Interpolated, Ramp # Interpolated waveform: smooth curve through specified values omega_wf = Interpolated(duration=10, values=[0, 1, 0]) # Constant waveform delta_wf = Constant(duration=10, value=-2) # Ramp waveform delta_wf = Ramp(duration=10, initial_value=-2, final_value=2) # Combine into a Drive drive = Drive( amplitude=omega_wf, detuning=delta_wf ) drive.draw() ``` -------------------------------- ### Create a Hexagonal Lattice Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Generates a hexagonal lattice graph with specified rows, columns, and spacing. Includes a call to draw the graph. ```python graph = DataGraph.hexagonal(m = 2, n = 2, spacing = 1.0) graph.draw() ``` -------------------------------- ### Initialize InteractionEmbedder Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Instantiate the InteractionEmbedder with default settings. This embedder is used to encode matrices into the interaction term of the Rydberg analog model. ```python from qoolqit.embedding import InteractionEmbedder embedder = InteractionEmbedder() print(embedder) ``` -------------------------------- ### Run Tests Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/CONTRIBUTING.md Execute the project's unit tests using pytest to ensure code correctness. ```shell pytest ``` -------------------------------- ### Define QUBO Matrix Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Initializes a NumPy array representing the QUBO matrix Q. This matrix defines the quadratic unconstrained binary optimization problem. ```python import numpy as np Q = np.array( [ [-10.0, 19.7365809, 19.7365809, 5.42015853, 5.42015853], [19.7365809, -10.0, 20.67626392, 0.17675796, 0.85604541], [19.7365809, 20.67626392, -10.0, 0.85604541, 0.17675796], [5.42015853, 0.17675796, 0.85604541, -10.0, 0.32306662], [5.42015853, 0.85604541, 0.17675796, 0.32306662, -10.0], ] ) ``` -------------------------------- ### Run Program on Emulator and Plot Distribution Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Executes a compiled program on an emulator and retrieves the simulation results, including the final bitstrings, which are then plotted. ```python job = emulator.run(program) results = job.results() counter = results.final_bitstrings plot_distribution(counter, marked_bitstrings) ``` -------------------------------- ### Classical QUBO Solution Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Computes the classical solutions for the QUBO problem by brute-forcing all possible bitstrings. This method is feasible only for small QUBO instances due to its exponential time complexity. ```python # Classical solution bitstrings = np.array([np.binary_repr(i, len(Q)) for i in range(2 ** len(Q))]) bitstring_lists = np.array([np.array(list(b), dtype=int) for b in bitstrings]) Q_upper = np.triu(Q) costs = np.array([z @ Q_upper @ z for z in bitstring_lists]) idx_sort = np.argsort(costs).tolist() sorted_costs = costs[idx_sort] sorted_bitstrings = bitstrings[idx_sort] print("Two best solutions: ", sorted_bitstrings[:2]) print("Respective costs: ", sorted_costs[:2]) # We save the two best solutions for plotting marked_bitstrings = sorted_bitstrings[:2] ``` -------------------------------- ### Checkout and Push New Branch Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/CONTRIBUTING.md Checkout your newly created branch and set it as the upstream branch on the GitHub server. ```shell git checkout / git push --set-upstream origin / ``` -------------------------------- ### Validate Custom Embedder Configuration Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/extended_usage/custom_embedders.ipynb Demonstrates how Qoolqit validates that configuration dataclass fields match the keyword arguments of the embedding function. An error is raised if there's a mismatch. ```python from dataclasses import dataclass from qoolqit.graph.data_graph import DataGraph from qoolqit.graph.embedders import GraphToGraphEmbedder, EmbedderConfig def my_embedding_function(graph: DataGraph, param1: float) -> DataGraph: return graph @dataclass class MyWrongConfig(EmbedderConfig): some_other_param: float = 1.0 try: wrong_embedder = GraphToGraphEmbedder(my_embedding_function, MyWrongConfig()) except TypeError as error: print(error) ``` -------------------------------- ### Create a Concrete Embedder Wrapper Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/extended_usage/custom_embedders.ipynb Create a concrete embedder wrapper class that inherits from a base embedder family. This allows for easier import and use of the custom embedder. ```python class MyNewEmbedder(GraphToGraphEmbedder): def __init__(self): super().__init__(my_embedding_function, MyEmbedderConfig()) ``` -------------------------------- ### Define Drive with Detuning Map Modulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Create a Drive object that includes a Detuning Map Modulator. This allows for custom detuning effects on qubits in addition to the main amplitude drive. The DMM waveform must be negative at all times. ```python drive = Drive(amplitude=Constant(10.0,1.0), dmm=dmm) print(drive) drive.draw() ``` -------------------------------- ### Draw Graph with Layout Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/graphs.ipynb Draw a graph using a specified layout. This method passes arguments to NetworkX's draw_networkx function. ```python import networkx as nx pos = nx.circular_layout(graph) graph.draw(pos=pos) ``` -------------------------------- ### Use Custom Waveform in Drive Instantiation Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/extended_usage/custom_waveforms.ipynb Integrate custom waveforms, like SmoothPulse, into a Drive object alongside other waveform types such as Ramp. This demonstrates composing complex pulse sequences. ```python from qoolqit import Drive, Ramp T = 2 * math.pi amplitude = SmoothPulse(T, omega_max=1.0) detuning = Ramp(T, -1.0, 1.0) drive = Drive(amplitude=amplitude, detuning=detuning) print(drive) drive.draw() ``` -------------------------------- ### Handle Detuning Too Large Compilation Error Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/compilation/error_handling.ipynb Demonstrates how to catch and print a CompilationError when the drive detuning is too large, exceeding device limits even after amplitude rescaling. ```python L=4 amp=1 det=20 program=create_program(L,amp,det) try: compiled_sequence = program.compile_to(device) except CompilationError as err: print(err) ``` -------------------------------- ### Create Qubit Register from Graph Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/tutorials/solving_a_qubo.ipynb Creates a qubit register from the embedded graph generated by the InteractionEmbedder. This register represents the problem in the Rydberg analog model. ```python # Create the register from qoolqit import Register register = Register.from_graph(embedded_graph) embedded_graph.draw() ``` -------------------------------- ### Perform Interaction Embedding and Visualize Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Embed a matrix using the InteractionEmbedder and convert the resulting DataGraph to a Register. The embedded graph and the register are then visualized. ```python import matplotlib.pyplot as plt from qoolqit import Register embedded_graph = embedder.embed(A) register = Register.from_graph(embedded_graph) embedded_graph.draw() register.draw() ``` -------------------------------- ### Create Detuning Map Modulator Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Instantiate a DetuningMapModulator with a waveform and a dictionary mapping qubit indices to modulation weights. This is used to define local detuning contributions for qubits. ```python from qoolqit.drive import DetuningMapModulator dmm_waveform = Constant(10.0, -1.0) dmm_weights = {0:0.1, 1:0.3, 2:0.8} dmm = DetuningMapModulator(dmm_waveform, dmm_weights) print(dmm) ``` -------------------------------- ### Configure SpringLayoutEmbedder Parameters Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/embedding.ipynb Modifies the configuration of the SpringLayoutEmbedder, such as setting the number of iterations and a random seed for reproducibility. The updated configuration is then printed. ```python embedder.config.iterations = 100 embedder.config.seed = 1 print(embedder) ``` -------------------------------- ### Define and Compose Drive Hamiltonian Source: https://github.com/pasqal-io/qoolqit/blob/main/docs/fundamentals/quantum_program.ipynb Creates a drive Hamiltonian by combining amplitude and detuning waveforms. The drive can be expanded through composition using the '>>' operator. Amplitude is required; detuning and phase default to zero if not provided. ```python from qoolqit import Constant, Drive, Interpolated # Defining two waveforms amplitude = Constant(duration=5.0, value=1.0) >> Interpolated(10.0, [0.0, 0.8, 0.8, 0.0]) detuning = Ramp(8.0, -1.0, 1.0) >> Constant(4.0, 1.0) # Defining the drive drive = Drive( amplitude = amplitude, detuning = detuning ) # Expanding the drive through composition drive = drive >> drive print(drive) ```