CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-qiskit

An open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.

Pending
Overview
Eval results
Files

primitives.mddocs/

Quantum Primitives

Qiskit's primitives provide the modern interface for quantum computation using the V2 interface. They offer two core computational primitives: StatevectorSampler for circuit execution and measurement, and StatevectorEstimator for expectation value calculation. This interface uses Primitive Unified Blocs (PUBs) for efficient vectorized computation.

Capabilities

Sampler V2 Primitive

The StatevectorSampler primitive executes quantum circuits and returns measurement samples, providing the foundation for sampling-based quantum algorithms.

class StatevectorSampler(BaseSamplerV2):
    def __init__(self, *, default_shots=1024, seed=None):
        """
        Initialize StatevectorSampler primitive (V2 interface).
        
        Parameters:
        - default_shots: Default number of measurement shots
        - seed: Random seed for reproducible results
        """
    
    def run(self, pubs, *, shots=None):
        """
        Execute primitive unified blocs (PUBs) and return measurement results.
        
        Parameters:
        - pubs: Primitive unified blocs - list of (circuit, parameter_values, shots) tuples
        - shots: Default shots for all PUBs (overridden by per-PUB shots)
        
        Returns:
        PrimitiveJob: Job object with result() method
        """

class BackendSamplerV2(BaseSamplerV2):
    def __init__(self, backend, *, default_shots=1024, seed=None):
        """
        Backend-based Sampler V2 implementation.
        
        Parameters:
        - backend: Quantum backend to execute circuits on
        - default_shots: Default number of shots
        - seed: Random seed
        """
    
    def run(self, pubs, *, shots=None):
        """Execute PUBs on backend."""
    
    @property
    def backend(self):
        """Backend used for execution."""
    
    @property
    def options(self):
        """Execution options."""

class SamplerPubResult(PubResult):
    """Result for a single PUB execution in sampler."""
    
    @property
    def data(self):
        """
        Measurement data as DataBin with register-named BitArrays.
        Access measurement outcomes via register names (e.g., result.data.c for register 'c').
        """
    
    @property
    def metadata(self):
        """PUB execution metadata."""

Estimator V2 Primitive

The StatevectorEstimator primitive calculates expectation values of observables on quantum states, essential for variational quantum algorithms and quantum chemistry.

class StatevectorEstimator(BaseEstimatorV2):
    def __init__(self, *, default_precision=0.015625, seed=None):
        """
        Initialize StatevectorEstimator primitive (V2 interface).
        
        Parameters:
        - default_precision: Default precision for expectation values
        - seed: Random seed for reproducible results
        """
    
    def run(self, pubs, *, precision=None):
        """
        Calculate expectation values for primitive unified blocs.
        
        Parameters:
        - pubs: List of (circuit, observables, parameter_values) tuples
        - precision: Target precision for expectation values
        
        Returns:
        PrimitiveJob: Job object with result() method
        """

class BackendEstimatorV2(BaseEstimatorV2):
    def __init__(self, backend, *, default_precision=0.015625, seed=None):
        """
        Backend-based Estimator V2 implementation.
        
        Parameters:
        - backend: Quantum backend to execute circuits on
        - default_precision: Default precision
        - seed: Random seed
        """
    
    def run(self, pubs, *, precision=None):
        """Calculate expectation values on backend."""
    
    @property
    def backend(self):
        """Backend used for execution."""
    
    @property
    def options(self):
        """Execution options."""

class EstimatorPubResult(PubResult):
    """Result for a single PUB execution in estimator."""
    
    @property
    def data(self):
        """
        Expectation value data as DataBin with evs array.
        Access expectation values via result.data.evs.
        """
    
    @property
    def metadata(self):
        """PUB calculation metadata."""

Base Classes

Abstract base classes defining the V2 primitive interfaces.

class BaseSamplerV2:
    """Abstract base class for V2 Sampler implementations."""
    
    def run(self, pubs, *, shots=None):
        """Run primitive unified blocs and return measurement results."""
        raise NotImplementedError

class BaseEstimatorV2:
    """Abstract base class for V2 Estimator implementations."""
    
    def run(self, pubs, *, precision=None):
        """Calculate expectation values for primitive unified blocs."""
        raise NotImplementedError

Primitive Jobs and Results

Job management and result handling for primitive execution.

class PrimitiveJob(BasePrimitiveJob):
    """Job object returned by primitive run() methods."""
    
    def result(self):
        """
        Get job result (blocking).
        
        Returns:
        PrimitiveResult: Execution results containing list of PubResults
        """
    
    def status(self):
        """Get job status."""
    
    def cancel(self):
        """Cancel the job if possible."""
    
    def running(self):
        """Check if job is currently running."""
    
    def done(self):
        """Check if job is completed."""

class PrimitiveResult:
    """Result from V2 primitive execution containing multiple PubResults."""
    
    def __getitem__(self, index):
        """Access individual PubResult by index."""
    
    def __len__(self):
        """Number of PubResults."""
    
    def __iter__(self):
        """Iterate over PubResults."""

class PubResult:
    """Base class for primitive unified bloc results."""
    
    @property
    def data(self):
        """Result data as DataBin."""
    
    @property
    def metadata(self):
        """Result metadata."""

Container Classes

Data structures for handling primitive inputs and outputs with V2 interface.

class BitArray:
    """Efficient storage of measurement bit arrays organized by classical register."""
    
    def __init__(self, array, num_bits, shape=None):
        """
        Initialize bit array.
        
        Parameters:
        - array: Array of measurement outcomes
        - num_bits: Number of bits per measurement
        - shape: Shape of measurement array
        """
    
    def get_counts(self, loc=None):
        """
        Get measurement counts dictionary.
        
        Parameters:
        - loc: Specific bit locations to count
        
        Returns:
        dict: Counts dictionary mapping bitstrings to frequencies
        """
    
    def get_bitstrings(self, loc=None):
        """Get measurement results as bit strings."""
    
    def slice_bits(self, indices):
        """Extract specific bit positions."""
    
    @property
    def shape(self):
        """Shape of the bit array."""
    
    @property
    def num_bits(self):
        """Number of bits per measurement."""
    
    @property
    def num_shots(self):
        """Number of measurement shots."""

class DataBin:
    """Container for primitive execution data with register-based access."""
    
    def __init__(self, **data):
        """Initialize data container with named data fields."""
    
    def __getattr__(self, name):
        """Access data fields as attributes (e.g., data.c for register 'c')."""
    
    def __getitem__(self, key):
        """Access data fields by key."""
    
    def keys(self):
        """Get data field names."""
    
    def values(self):
        """Get data field values."""
    
    def items(self):
        """Get (name, value) pairs."""

Primitive Unified Blocs (PUBs)

Input specification format for V2 primitives enabling vectorized computation.

# Type aliases for PUB specifications
SamplerPubLike = Union[
    QuantumCircuit,                              # Simple circuit
    Tuple[QuantumCircuit, ArrayLike],           # Circuit with parameter values
    Tuple[QuantumCircuit, ArrayLike, int],      # Circuit with parameters and shots
]

EstimatorPubLike = Union[
    Tuple[QuantumCircuit, ObservablesArrayLike],                    # Circuit and observables
    Tuple[QuantumCircuit, ObservablesArrayLike, ArrayLike],        # With parameter values
]

ObservablesArrayLike = Union[
    str,                           # Pauli string
    SparsePauliOp,                # Sparse Pauli operator
    List[Union[str, SparsePauliOp]], # List of observables
]

BindingsArrayLike = Union[
    Mapping[Parameter, float],     # Single parameter binding
    Sequence[Mapping[Parameter, float]], # Multiple parameter sets
    ArrayLike,                     # Array of parameter values
]

Usage Examples

from qiskit.primitives import StatevectorSampler, StatevectorEstimator
from qiskit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp
import numpy as np

# Basic V2 Sampler usage
circuit = QuantumCircuit(2, 2, name='bell')
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()

sampler = StatevectorSampler()
job = sampler.run([circuit], shots=1000)
result = job.result()
pub_result = result[0]  # First (and only) PUB result

# Access measurement data by register name
counts = pub_result.data.c.get_counts()  # 'c' is the classical register name
print(f"Measurement counts: {counts}")

# Parameterized circuit with V2 interface (PUB format)
theta = Parameter('θ')
param_circuit = QuantumCircuit(1, 1)
param_circuit.ry(theta, 0)
param_circuit.measure_all()

# Run with multiple parameter values using PUB format
angles = [[0], [np.pi/4], [np.pi/2], [np.pi]]
job = sampler.run([(param_circuit, angles)], shots=1024)
result = job.result()

# Access results for different parameter values
param_result = result[0]
measurement_data = param_result.data.c  # BitArray with shape matching parameter array
for i, angle in enumerate([0, np.pi/4, np.pi/2, np.pi]):
    counts = measurement_data.get_counts(i)  # Get counts for i-th parameter set
    print(f"θ = {angle:.2f}: {counts}")

# V2 Estimator usage with PUB format
observable = SparsePauliOp.from_list([('ZZ', 1.0), ('XX', 0.5)])
prep_circuit = QuantumCircuit(2)
prep_circuit.h(0)
prep_circuit.cx(0, 1)  # Bell state preparation

estimator = StatevectorEstimator()
job = estimator.run([(prep_circuit, observable)])
result = job.result()
expectation_value = result[0].data.evs[0]  # Access expectation values via .evs
print(f"Expectation value: {expectation_value}")

# Vectorized estimator computation
multiple_observables = [
    SparsePauliOp.from_list([('ZZ', 1.0)]),
    SparsePauliOp.from_list([('XX', 1.0)]),
    SparsePauliOp.from_list([('YY', 1.0)])
]

# Single PUB with multiple observables (vectorized)
job = estimator.run([(prep_circuit, multiple_observables)], precision=0.01)
result = job.result()
expectation_values = result[0].data.evs  # Array of expectation values
print(f"Multiple expectations: {expectation_values}")

# Variational algorithm example with V2 primitives
def ansatz_circuit(params):
    circuit = QuantumCircuit(2)
    circuit.ry(params[0], 0)
    circuit.ry(params[1], 1)
    circuit.cx(0, 1)
    circuit.ry(params[2], 0)
    circuit.ry(params[3], 1)
    return circuit

# Hamiltonian for optimization
hamiltonian = SparsePauliOp.from_list([
    ('ZZ', 1.0),
    ('XX', 0.5), 
    ('YY', 0.5),
    ('ZI', -0.1),
    ('IZ', -0.1)
])

# Multiple parameter sets in a single PUB for efficiency
param_sets = [
    [0, 0, 0, 0],
    [np.pi/4, np.pi/4, np.pi/4, np.pi/4],
    [np.pi/2, 0, np.pi/2, 0]
]

ansatz = ansatz_circuit([Parameter(f'θ{i}') for i in range(4)])
job = estimator.run([(ansatz, hamiltonian, param_sets)])
result = job.result()

# Access energy values for all parameter sets at once
energies = result[0].data.evs
for i, params in enumerate(param_sets):
    print(f"Parameters {params}: Energy = {energies[i]:.4f}")

# Backend execution with V2 primitives
from qiskit.primitives import BackendSamplerV2, BackendEstimatorV2
from qiskit.providers.fake_provider import FakeManila

backend = FakeManila()
backend_sampler = BackendSamplerV2(backend)

# V2 backend execution
job = backend_sampler.run([circuit], shots=2048)
result = job.result()
backend_counts = result[0].data.c.get_counts()
print(f"Backend execution result: {backend_counts}")

Install with Tessl CLI

npx tessl i tessl/pypi-qiskit

docs

circuit-construction.md

circuit-formats.md

gates-operations.md

index.md

primitives.md

providers.md

quantum-information.md

synthesis.md

transpilation.md

visualization.md

tile.json