Registers#

QCDL supports integer and fixed-point registers you can use for simple classical expressions (e.g., multiplication and XOR), and comparisons. The Classical Registers & Arithmetic section introduces registers.

class Array(modules: Sequence[QCDLModule], initial_value: Any, name: str | None = None, dtype: str = 'int', master_kwargs: dict[str, Any] | None = None, alias: bool | str = False, ignore_reallocation: bool = False, signed: bool = True, scope_id: int | None = None)[source]#

Bases: RegisterInitializerMixin

An array of contiguous addresses in memory.

You can use an array to access a register, such as the FixedPointRegister and Register class registers, based on its index in a list.

Warning

The compiler does not check bounds for your access. Use with care.

Parameters:
  • modules – Modules, typically qubits, associated with the register.

  • initial_value – Initial values. An integer initializes a list of zeros of that length. A list or NumPy array sets a number of values that depends on its length.

  • name – Optional name for the register.

  • dtype –

    Type of registers in the array. Defaults to “int”. Supported values are:

    • ”int”: Integer.

    • ”float”: Floating point.

  • master_kwargs – Propagate this to the master instruction. This parameter is intended for use by developers of QCDL.

  • alias – Set to True if you are aliasing an existing register, and for type punning reuse that register’s name in the name parameter. Aliased registers are not reinitialized.

  • ignore_reallocation – If True, the compiler does not reallocate if already allocated (and does not raise an exception).

Note

The assignment operator is not <<= for arrays.

Examples

This example uses an array to access and set register values.

import numpy as np
from dwave.gate.qcdl import qcdl, Scope
from dwave.gate.qcdl.operations import measure

@qcdl(2)
def array_example(q0, q1):
    # Create an array of 10 integers, with initial values 0, 1, 2, 3, ...
    arr = Scope.Array(np.arange(10))
    # Create registers
    sc = Scope(q0, q1)
    r1 = sc.Register(3)
    r2 = scope.Register()
    # r gets the value of the array at the index of the current value of r1
    r <<= arr[r1]
    # Set the value of the array at index r1 to 0
    arr[r1] = 0     # Note the assignment operator is not <<=

qcdl_program = array_example()
class ExpressionAggregator(modules: Sequence[QCDLModule], master_kwargs: dict[str, Any] | None = None, scope_id: int | None = None)[source]#

Bases: object

Combine several expressions into one CPU program.

This class is intended for use by developers of QCDL and advanced users.

This class can reduce the number of QCDL instructions. Its primary use is for GOF category of QPU registers (see the Output class), where the number of instruction set architecture (ISA) instructions must be controlled.

Parameters:
  • modules – Module, typically qubits.

  • master_kwargs – Forwarded to the master instruction that is emitted. Defaults to None. This parameter is intended for use by developers of QCDL.

Examples

from dwave.gate.qcdl import qcdl, Scope
from dwave.gate.qcdl.registers import ExpressionAggregator

@qcdl(2)
def aggregate_example(q0, q1):
    sc = Scope(q0, q1)
    r0 = sc.Register(name="r0")
    r1 = sc.Register(name="r1")

    with ExpressionAggregator(sc.qcdl_modules):
        # These two instructions are aggregated into one QCDL instruction
        r0 <<= 1
        r1 <<= r0

qcdl_program = aggregate_example()
class FixedPointRegister(modules: Sequence[QCDLModule], initial_value: float = 0.0, name: str | None = None, master_kwargs: dict[str, Any] | None = None, alias: bool | str = False, ignore_reallocation: bool = False, scope_id: int | None = None)[source]#

Bases: NumberOpsMixin, AssignmentOpsMixin, RegisterInitializerMixin, Target

Fixed-point register.

Supports a range of values between -2, inclusive, to 2, non-inclusive (\([-2,2)\) or \([-2, 2 - 2^{-16}]\)). This is Q2.16 in Q notation: the register’s 18 bits use 1 bit for the sign, 1 for a digit to the left of the decimal, and 16 bits to the right of the decimal, giving a resolution of \(2^{-16}\).

Note

The dual-rail simulator in the Leap service supports floating-point numbers for this register.

The Classical Registers & Arithmetic section introduces registers. Use the <<= (in-place left shift) operator to assign a value to a register. See the mixin classes for supported operations and the Register class on using the alias argument for type punning.

Parameters:
  • modules – Modules where this register is created, typically representing one or more qubits. Typically, you create a register from a Scope object, which handles this parameter for you.

  • initial_value – Initial value. Defaults to 0.0.

  • name – Name for this register; useful for troubleshooting. If None, a name is generated. See the alias parameter for type punning.

  • master_kwargs – Propagate this to the master instruction. This parameter is intended for use by developers of QCDL.

  • alias – Set to True if you are aliasing an existing register, and for type punning reuse that register’s name in the name parameter. Aliased registers are not reinitialized.

  • ignore_reallocation – If True, the compiler does not reallocate if already allocated (and does not raise an exception).

  • scope_id – Identity of the Scope this register is derived from. The FixedPointRegister() method sets this value when you create a register from a Scope instance.

Examples

This is a typical example of instantiating a register from a Scope object for the relevant qubits.

from dwave.gate.qcdl import qcdl, Scope
from dwave.gate.qcdl.operations import measure

@qcdl(2)
def create_fixed_reg(q0, q1):
    sc = Scope(q0, q1)
    r0 = sc.Register(name="r0")
    r1 = sc.FixedPointRegister(name="r1")
    r1 <<= 1.274
    q0.h()
    measure(q0, register=r0)

qcdl_program = create_fixed_reg()

See additional examples in the Register class.

See:

Fixed-point arithmetic and Q number format

class Output(modules: Sequence[QCDLModule], name: str | None = None, category: str | None = None, master_kwargs: dict[str, Any] | None = None, scope_id: int | None = None)[source]#

Bases: Target

Outputs for writing.

This class is intended for use by developers of QCDL and advanced users.

You can write data to these outputs but not read from them. For usage, see the append_table_row() method.

Parameters:
  • modules – Modules, typically qubits.

  • name – Reserve a specific name. Defaults to None.

  • category –

    Category of registers. Defaults to None. Supported values are:

    • DYN

    • GOF

  • master_kwargs – Propagate this to the master instruction. This parameter is intended for use by developers of QCDL.

class Register(modules: Sequence[QCDLModule], initial_value: int = 0, name: str | None = None, master_kwargs: dict[str, Any] | None = None, alias: bool | str = False, ignore_reallocation: bool = False, scope_id: int | None = None)[source]#

Bases: IntegerOpsMixin, AssignmentOpsMixin, RegisterInitializerMixin, Target

18-bit signed integer register.

Supports a range of values between -131,072 and 131,071 (\([-2^{17}, 2^{17-1}]\))).

Note

The dual-rail simulator in the Leap service supports floating-point numbers for this register.

The Classical Registers & Arithmetic section introduces registers. Use the <<= (in-place left shift) operator to assign a value to a register. See the mixin classes for supported operations.

Aliasing

You can alias registers, meaning that two registers point to the same memory address. This can be useful if, for example, you want to use the Register interface to manipulate memory already allocated by another register; a specialized use case is using bitwise operators on a FixedPointRegister. This is supported with type punning, as shown in the example below.

Parameters:
  • modules – Modules where this register is created, typically representing one or more qubits. Typically, you create a register from a Scope object, which handles this parameter for you.

  • initial_value – Initial value. Defaults to 0.

  • name – Name for this register; useful for troubleshooting. If None, a name is generated. See the alias parameter for type punning.

  • master_kwargs – Propagate this to the master instruction. This parameter is intended for use by developers of QCDL.

  • alias – Set to True if you are aliasing an existing register, and for type punning reuse that register’s name in the name parameter. Aliased registers are not reinitialized.

  • ignore_reallocation – If True, the compiler does not reallocate if already allocated (and does not raise an exception).

  • scope_id – Identity of the Scope this register is derived from. The Register() method sets this value when you create a register from a Scope instance.

Examples

This example shows operations between registers.

from dwave.gate.qcdl import qcdl, Scope

@qcdl(2)
def register_ops(q0, q1):
    sc = Scope(q0, q1)
    r1 = sc.Register(initial_value=2, name="r1") # name for debugging
    r2 = sc.Register()
    r2 <<= 1                            # set r2 to 1
    r2 <<= 2 * r1                       # set r2 to 2*r1

qcdl_program = register_ops()

This example demonstrates type punning.

from dwave.gate.qcdl import qcdl, Scope

@qcdl(2)
def punning(q0, q1):
    sc = Scope(q0, q1)
    fr = sc.FixedPointRegister(initial_value=1, name="fr")
    ir = sc.Register(name="fr", alias=True)
    ir += ir & 4

qcdl_program = punning()

This example instantiates a register directly for qubit q0 and sets its scope_id to a Scope that includes that qubit.

from dwave.gate.qcdl import qcdl, Register, Scope

@qcdl(2)
def direct(q0, q1):
    sc = Scope(q0, q1)
    r1 = Register(q0, initial_value=2, name="r1", scope_id=sc.scope_id)

qcdl_program = direct()
validate_name(name: str) → None[source]#

Check if the specified string is valid as a name for a register.

Parameters:

name – Proposed register name.

Raises:

QCDLUserError – If the string is not supported for a register name.

Examples

from dwave.gate.qcdl.registers import validate_name

validate_name("r0")
validate_value(value: Any, dtype: str | type, signed: bool = True) → None[source]#

Check if the specified value can be assigned to a register.

Note

This is a convenience function you can use from Python to check your QCDL program.

Raises:

QCDLUserError – If the assignment is not supported.

Parameters:
  • value – Value or array of values to validate.

  • dtype – int or float.

  • signed – Only integers may be unsigned.

Examples

from dwave.gate.qcdl.registers import validate_value

validate_value(1.5, dtype=float)

Mixin Classes#

class IntegerOpsMixin[source]#

Supported operations for integers.

Used by the Register class.

  • \(<<=\) (assignment)

  • \(==, !=, <, >, <=, >=\)

  • \(+, -, *\)

  • \(\&, |\), ^ (bitwise operations)

  • right shift

class NumberOpsMixin[source]#

Supported operations for floats.

Used by the FixedPointRegister class.

  • \(<<=\) (assignment)

  • \(==, !=, <, >, <=, >=\) (equality)

  • \(+, -, *\) (standard arithmetic)