Skip to content

Custom Backends

The AliceBobLocalProvider allows you to create custom quantum backends with your own parameters, Pauli noise models, and timing models. This gives you full control over backend behavior while leveraging the existing infrastructure.

Overview

Custom backends enable you to:

  • Define custom backend parameters (e.g., kappa_1, kappa_2, average_nb_photons, or any parameters you need)
  • Implement custom Pauli noise models for specific quantum gates
  • Set custom timing models for gate operations

Quick Start

In this example, we will build a custom backend in which the X and measurement gates both:

  • Feature a X error with probability 0.1
  • Take 1e-6 second to execute

1. Create a Local Provider and Build Your Models

from qiskit_alice_bob_provider import AliceBobLocalProvider

local = AliceBobLocalProvider()

def x_error(gate_params, backend_params):
  return {
      'X': backend_params['p'],
  }

def x_time(gate_params, backend_params):
  return 1e-6

def measure_error(gate_params, backend_params):
  return {
      'X': backend_params['p'],
  }

def measure_time(gate_params, backend_params):
  return 1e-6

2. Build Your Custom Backend

custom_cat = local.build_custom_backend(
    backend_parameters={
        'n_qubits': 40,  # Mandatory
        'p': 0.1,
    },
    noise_models={
        'x': x_error,
        'mz': measure_error,
        },
    time_models={
        'x': x_time,
        'mz': measure_time,
    }
)

3. Run a Circuit on Your Custom Backend

from qiskit import QuantumCircuit

circ = QuantumCircuit(1,1)
circ.x(0)
circ.measure(0,0)

job = custom_cat.run(circ, shots=1000)
print(job.result().get_counts())

The output of the code above should be close to {'0': 180, '1': 820}, as the expected outcome is:

  • No error with probability \(0.9^2 = 0.81\)
  • One X error with probability \(2*0.9*0.1 = 0.18\)
  • Two X errors with probability \(0.1^2 = 0.01\), cancelling each other out

Note that you need to specify a noise and time model for each gate you use.

Function Reference

build_custom_backend()

Creates a custom quantum backend with specified parameters and models.

Parameters

Parameter Type Description
name str | None Name identifier for the custom backend
backend_parameters dict[str, Any] | None Backend-specific parameters (e.g., physical constants, device characteristics)
noise_models dict[str, NoiseFunction] | None Gate-specific noise functions mapping gate names to noise models
time_models dict[str, TimeFunction] | None Gate-specific timing functions mapping gate names to duration models
validate_parameters Callable[[dict[str, float]], bool] | None Optional function to validate backend parameters
default_1q_noise_model NoiseFunction | None Default noise model applied to all single-qubit gates
default_1q_time_model TimeFunction | None Default timing model applied to all single-qubit gates

Function Types

NoiseFunction:

  • Signature: (gate_parameters: list[float], backend_parameters: dict[str, Any]) -> dict[str, float]
  • Returns: Dictionary with 'X', 'Y', 'Z' Pauli error probabilities
  • Alternative: Parameter-less function () -> dict[str, float] for constant noise

TimeFunction:

  • Signature: (gate_parameters: list[float], backend_parameters: dict[str, Any]) -> float
  • Returns: Gate execution time in appropriate units
  • Alternative: Parameter-less function () -> float for constant duration

Complete Example

Here is a mode complete example with a 2-qubit gate and default noise and time models.

Step 1: Define Custom Functions

from qiskit_alice_bob_provider import AliceBobLocalProvider

local = AliceBobLocalProvider()

def default_error(gate_params, backend_params):
  return {
      'X': backend_params['p'],
  }

def default_time(gate_params, backend_params):
  return 1e-6

def measure_error(gate_params, backend_params):
  return {
      'X': backend_params['p'],
  }

def cx_error(gate_params, backend_params):
  return {
      'XI': backend_params['p'],
      'XX': backend_params['p'],
  }

def cx_time(gate_params, backend_params):
  return 1e-6

Step 2: Create the Backend

custom_cat = local.build_custom_backend(
    name='Custom Cat Backend',
    backend_parameters={
        'n_qubits': 40,  # Mandatory
        'p': 0.1,
    },
    noise_models={
        'mz': measure_error,
        'cx': cx_error,
        },
    time_models={
        'mz': measure_time,
        'cx': default_time
    },
    default_1q_noise_model=default_error,
    default_1q_time_model=default_time
)

3. Run a Circuit on Your Custom Backend

from qiskit import QuantumCircuit

circ = QuantumCircuit(2,1)
circ.x(1)
circ.cx(0,1)
circ.measure(1,0)

job = custom_cat.run(circ, shots=1000)
print(job.result().get_counts())

The output of the code above should be close to {'0': 244, '1': 756}, as the expected outcome on the second qubit is:

  • No error with probability \(0.9^3 = 0.729\)
  • One X error with probability \(3*0.9^2*0.1 = 0.243\)
  • Two X errors with probability \(3*0.9*0.1^2 = 0.027\), cancelling each other out
  • Three X errors with probability \(0.1^3 = 0.0001\), yielding a X error

Note that the noise model used for the X gate was the default noise model here. But if you specify a noise model for the X gate, it will override the default noise model.