# Config¶

 trueq.Config Contains the relevant configuration of a system, including which gates are available to be run, how many systems there are and the dimension of the individual systems. trueq.config.GateFactory Stores the YAML-like formatted description of a gate and allows for the creation of new NativeGates. trueq.config.InvolvingRule A dictionary containing allowable sets of systems. trueq.config.factory.parse_func Creates a python function from a string containing numbers, variables, and standard math functions.

## Config¶

class trueq.Config(conf)

Contains the relevant configuration of a system, including which gates are available to be run, how many systems there are and the dimension of the individual systems. See documentation for description of construction of the configuration file.

A minimal example .yaml file is presented below. The YAML below defines a four-qubit system, where the gates available are:

• Arbitrary $X(\phi)$ rotations, which cannot be applied while the neighboring qubits are in use.

• Arbitrary $Z(\phi)$ rotations, which can be applied in parallel with anything

• CNOT, which can never be used in parallel with any other gate.

Note that gates can either be defined by the Hamiltonian or Matrix keyword, but never both.

Since we allow arbitrary functional definition of gates using functions that can be parsed using parse_func, the Config object can be used to generate new NativeGate objects on the fly based upon the variables defined in the YAML.

Here we use a convenience method to create a basic config sufficient for most uses:

import trueq as tq
config = tq.Config.basic(name="Example", entangler=tq.Gate.cnot, mode="ZXZXZ")

# we can access the GateFactory objects via the factories attribute.
config.factories

# for ease of use, individual factories are available as attributes of the config
config.Z

# lets make an Z90 gate using this definition:
config.Z(phi=90)

Name:
• Example.Z
Aliases:
• Gate.s
• Gate.cliff9
Parameters:
• phi = 90
Generators:
• 'Z': 90.0
Matrix:

These configs can be saved to a YAML file and loaded back in the future. This facilitates including topology and gate restrictions by specifying Involving keys in the YAML.

import trueq as tq

file_contents = '''
Name: Example
Dimension: 2
Mode: ZXZXZ
Gate X:
Hamiltonian:
- ['X', phi]
Involving:
(0,) : (1, 2)
(1,) : (0, 2)
(2,) : (1, 3)
(3,) : (2,)
Gate Z:
Hamiltonian:
- ['Z', phi]
Involving:
(0,) : ()
(1,) : ()
(2,) : ()
(3,) : ()
Gate CNOT:
Matrix:
- [1, 0, 0, 0]
- [0, 1, 0, 0]
- [0, 0, 0, 1]
- [0, 0, 1, 0]
Involving:
(0, 1) : (2, 3)
(1, 2) : (0, 3)
(2, 3) : (0, 1)'''

# Configs can be loaded from either a filename, or the contents of a file:
tq.Config(file_contents)

Name: Example
Mode: ZXZXZ
Dimension: 2
Gate X:
Hamiltonian:
- [X, phi]
Involving: {'(0,)': '(1, 2)', '(1,)': '(0, 2)', '(2,)': '(1, 3)', '(3,)': '(2,)'}
Gate Z:
Hamiltonian:
- [Z, phi]
Involving: {'(0,)': (), '(1,)': (), '(2,)': (), '(3,)': ()}
Gate CNOT:
Matrix:
- ['1', '0', '0', '0']
- ['0', '1', '0', '0']
- ['0', '0', '0', '1']
- ['0', '0', '1', '0']
Involving: {'(0, 1)': '(2, 3)', '(1, 2)': '(0, 3)', '(2, 3)': '(0, 1)'}


The above config contains information about physical limitations of the gates. This information is encoded in the Involving key inside of the gate definitions. This involving key is a dictionary whose keys are the sets of systems on which the gate can act. In the YAML example above, the X gate can be applied to any of qubits 0, 1, 2, 3.

The values of the dictionary list which systems cannot have any gates applied to them while the gate acts on the systems specified by the key. For example, when the X gate in the above config is run on qubit 0, no other gates may be applied in parallel on either qubit 1 or 2.

This Involving information is used during compilation to ensure that circuits are compatable with the physical limitations of the hardware.

Parameters

conf (str) – Path to a configuration YAML file, or a parsed YAML file as a string.

static basic(name, entangler=Gate.cx, mode='ZXZXZ', dim=2)

Create a new Config object containing a fixed entangling gate and the Pauli rotation gates required to decompose single-qubit gates into the specified mode.

Parameters
• name (str) – Name of the configuration.

• entangler (Gate) – The entangling gate.

• mode (str) – The single qubit decomposition mode, defaults to 'ZXZXZ'

• dim (int) – The dimension of computational system, defaults to 2 (qubits)

Return type

Config

static from_params(name, mode='ZXZXZ', dim=2, factories=None)

Create a new Config object from the given parameters; an alternate constructor that bypasses the YAML input.

Parameters
• name (str) – Name of the configuration.

• mode (str) – The single qubit decomposition mode, defaults to 'ZXZXZ'

• dim (int) – The dimension of computational system, defaults to 2 (qubits)

• factories (Iterable) – An iterable of GateFactory objects.

Return type

Config

subset(labels=None, names=None, strict=True)

Create a new Config object containing a subset of the gate factories present in this configuration, and each of whose involving rules has been trimmed based on the given labels.

import trueq as tq

# create an basic config using cz gates as the entangler
config = tq.Config.basic("example", entangler=tq.Gate.cz)

# make a new config acting only on qubits 2, 3 restricted to gates z, cz
config.subset(labels=[2, 3], names=["z", "cz"])

Name: example
Mode: ZXZXZ
Dimension: 2
Gate cz:
Matrix:
- [(1+0j), 0j, 0j, 0j]
- [0j, (1+0j), 0j, 0j]
- [0j, 0j, (1+0j), 0j]
- [0j, 0j, 0j, (-1+0j)]
Involving: {}

Parameters
• labels (Iterable) – The labels to be present in the new config. If None, no filtering based on labels is done.

• names (Iterable) – A list of gate factory names to keep. If None, no filtering based on factory names is done.

• strict (bool) – Whether to filter gate factories based on being a strict subset of the given labels (True), or based on overlapping with labels at all (False).

Return type

Config

static make_config(multiqubit_fact, parameters, name, mode='ZXZ')

A convenience method for making a configuration file for a quantum system with fixed multi-qubit gates with nonhomogenous parameters.

import trueq as tq
iSwapLike_mat = [[1, 0, 0, 0],
[0, 0, -1j, 0],
[0, -1j, 0, 0],
[0, 0, 0, "exp(-1j * phi / 180)"],
]
iSwapLike_factory = tq.config.GateFactory("iSwapLike", matrix=iSwapLike_mat)
parameters = {(0, 1): 90, (2, 3): 45}
conf = tq.Config.make_config(iSwapLike_factory, parameters, "Example")
conf.iSwapLike_0_1()

Name:
• Example.iSwapLike_0_1
Likeness:
• Non-Clifford
Generators:
• 'IZ': -14.324
• 'XX': 90.0
• 'YY': 90.0
• 'ZI': -14.324
• 'ZZ': 14.324
Matrix:
Parameters
• multiqubit_fact (GateFactory) – A gate factory that can generate the nonhomogenous gates that can be implemented in the system.

• parameters (dict) – A dictionary mapping tuples of qubit labels to parameters of the given mulit-qubit factory to be used on those particular qubits.

• name (str) – The name for the resulting config file.

• mode (str) – The mode used to decompose single-qubit operations.

Return type

Config

property dim

The dimension of systems (e.g., 2 for qubits, 3 for qutrits).

Return type

int

property mode

The mode by which arbitrary single-qubit gates are decomposed in the system to native gates.

Return type

str

property name

Name of this device configuration.

Return type

str

property connectivity

The connectivity graph of all multi-qubit gates in the config.

A set of frozensets which contain all multi-qubit connections defined by the factories present in the config.

Type

set

to_dict()

Returns a dictionary representation of the Config.

Return type

dict

to_yaml()

Returns a YAML representation of the Config.

Type

str

## Gate Factory¶

class trueq.config.GateFactory(name, matrix=None, hamiltonian=None, involving=None, conf_name=None, parameters=None)

Stores the YAML-like formatted description of a gate and allows for the creation of new NativeGates. This is useful when you have a functional description of a gate such as $X(\theta)$ which would be an arbitrary rotation around the X axis by some angle $\theta$. Either a unitary matrix definition or hamiltonian description of the gate may be provided, but not both.

import trueq as tq
y_factory = tq.config.GateFactory(name='y', hamiltonian=[['Y', 'phi']])
y_factory(phi=90)

Name:
• GateFactory.y
Aliases:
• Gate.cliff7
Parameters:
• phi = 90
Generators:
• 'Y': 90.0
Matrix:
import trueq as tq
iSwap_matrix = [[1,  0,  0,                          0],
[0,  0,-1j,                          0],
[0,-1j,  0,                          0],
[0,  0,  0,'exp(-1j * phi * pi / 180)']]
iSwap_factory = tq.config.GateFactory(name="iSwapLike", matrix=iSwap_matrix)
iSwap_factory(phi=45)

Name:
• GateFactory.iSwapLike
Likeness:
• Non-Clifford
Parameters:
• phi = 45
Generators:
• 'IZ': -22.5
• 'XX': 90.0
• 'YY': 90.0
• 'ZI': -22.5
• 'ZZ': 22.5
Matrix:
Parameters
• name (str) – Name of the gate operation which must be a valid identifier examples: CZ, X, CNOT.

• matrix (list) – A unitary matrix description of the gate, can include string function definitions which will be parsed into a Gate when the factory is called.

• hamiltonian (list) – A hamiltonian generator description of the gate, as described in the Gate object. However the values can be strings which are parsable into values.

• involving (dict) – A dictionary describing the limitations of the gate, see Config description for a more in-depth description.

• conf_name (str) – Used for correctly generating repr, used primarily by Config.

• parameters (list) – An optional list of the parameters present in the definition, this allows for the preferred ordering of the parameters to be specified. If None is provided, then parameter names are inferred from the definition in an arbitrary order.

subset(labels=None, strict=True)

Creates a new GateFactory object with a set of involving rules that is a subset of this factory’s rules.

import trueq as tq
import numpy as np

involving = {(0, 1): (2, 3), (1, 2): (3,), (2, 3): (1,), (3, 8): ()}
factory = tq.config.GateFactory(
name="cz", matrix=np.diag([1, 1, 1, -1]), involving=involving
)

subset = factory.subset(labels=(0, 1, 2), strict=True)
assert subset.involving.rules == {(0, 1): (2, 3), (1, 2): (3,)}
subset

GateFactory(name='cz', matrix=[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]], involving=InvolvingRule(rules={(0, 1): (2, 3), (1, 2): (3,)}, default_allow=False))

Parameters
• labels (Iterable) – The labels to be present in the new config. If None, no filtering based on labels is done.

• strict (bool) – Whether to filter involving labels based on being a strict subset of the given labels (True), or based on overlapping with labels at all (False).

Return type

Config

property single_qubit_axis

If this factory is a simple qubit rotation about a single Pauli axis, then this is a tuple (axis, angle) where axis is one of 'XYZ', and angle is the rotation angle in degrees if a fixed gate. This is None if this factory doesnt appear to be a single qubit rotation.

Cases where this property is None:

• If this factory is not a simple rotation about a single Pauli axis.

• If this factory a simple qubit rotation but the single parameter is not in terms of degrees.

Type

tuple | None

get_gate(*args, **kwargs)

Returns a NativeGate based upon the parameters provided.

Since gates are defined by text strings, some live parsing is done on this text description to generate the NativeGate object.

Note

If the gate is defined by only one parameter, it is not required to provide the keyword, the parameter is inferred from what is expected. Otherwise all parameters must be specified in full by their keywords. Constructed NativeGate objects are memoized and cached based upon the kwargs.

Return type

NativeGate

find_closest(gate)

Given a Gate object, optimize the Factory parameters such that we get the closest gate possible up to a global phase.

Returns the closest gate possible, as well as the error.

Note

For this function, ‘close’ is defined by the Frobenius norm of (Gate.adj @ Factory(**params)).mat - I where a global phase is removed from the matrix product.

Parameters

gate (Gate) – A Gate

Return type

tuple

property n_sys

The number of systems this gate factory acts on.

Type

int

property dim

The dimension of gates produced by this factory, e.g., 2 for a single qubit, 4 for two qubits, etc.

Type

int

property parameters

The list of all the parameters in the functional definition of the gate.

Type

list

property n_params

The number of parameters in the functional definition of the gate.

Type

int

property involving

A specification of which systems can be involved in the gate operation.

Type

InvolvingRule

to_dict()

Returns a dictionary representation of the factory object.

Return type

dict

## Involving Rule¶

class trueq.config.InvolvingRule(rules=None, default_allow=None)

A dictionary containing allowable sets of systems.

from trueq.config import InvolvingRule

# In the default case, any involving check returns as valid
rule = InvolvingRule()

(5, ) in rule,  rule[(1, 5)]

(True, ())

from trueq.config import InvolvingRule

# In the case where rules are provided, it will return the rules
rule = InvolvingRule(rules={(0,): (2, 3, 4)})

rule[(0,)], (1, ) in rule

((2, 3, 4), False)

from trueq.config import InvolvingRule

# In the case where rules are provided, and default_allow=True
# and will return True for all other cases
rule = InvolvingRule(rules={(0,): (2, 3, 4)}, default_allow=True)

rule[(0,)], rule[(1,)]

((2, 3, 4), ())


See Config for more details on how these rules are used.

Parameters
• rules (dict) – A dictionary with both keys and values being tuples of ints. The key represents allowed operations, and the values represent blocking operations that get placed on other qubits due to the key labels.

• default_allow (bool | None) – Defines the behavior if a key is not present in the ruleset. If True, then if a key is not found in the rules, InvolvingRule acts as though it were present. If False, InvolvingRule raise KeyErrors. If None, then default_allow is set to True if no rules are provided, and False if rules are provided.

keys()

Returns the keys for given rules.

Return type

generator of tuple

values()

Returns the values for given rules.

Return type

generator of tuple

items()

Returns the key, value pairs for given rules.

Return type

generator of tuple

unordered_get(key)

Gets the value associated with a given key, regardless of the ordering.

This returns a list of tuples, where the tuples contain the required ordering as defined by the rules, along with the value associated with that key.

from trueq.config import InvolvingRule
rule = InvolvingRule(rules={(0, 1): (2, 3, 4)})

rule.unordered_get((1, 0))

[((0, 1), (2, 3, 4))]


This is useful when connectivity matters, but not the strict ordering of labels.

Parameters

key (tuple) – The key to fetch, must be a tuple of ints.

Return type

tuple

unordered_contains(key)

Determines if any permutation of the given key is present in rules.

from trueq.config import InvolvingRule
rule = InvolvingRule(rules={(0, 1): (2, 3, 4)})

rule.unordered_contains((1, 0))

True


This is useful when connectivity matters, but not the strict ordering of labels.

Parameters

key (tuple) – The key to fetch, must be a tuple of ints.

Return type

bool

## Parsing functions¶

trueq.config.factory.parse_func(func_str)

Creates a python function from a string containing numbers, variables, and standard math functions.

from trueq.config.factory import parse_func, KNOWN_FUNCTIONS
f = parse_func('5*sin(x) + y')
print(f(x=np.pi, y=1))

# all functions in KNOWN_FUNCTIONS can be parsed
print(KNOWN_FUNCTIONS.keys())

1.0000000000000007
dict_keys(['sin', 'cos', 'tan', 'exp', 'sqrt', 'arcsin', 'arccos', 'arctan', 'round', 'ceil', 'floor', 'int', 'float', 'complex', 'pi', 'list', 'tuple', 'dict', 'set'])


Note

Parsing functions adds an overhead relative to directly calling numpy functions. The overhead is approximately a factor of 20 for simple functions.

Parameters

func_str (str) – A string describing the function to be created.

## Pre-Defined factories¶

factory.u1_factory = GateFactory(name='U1Gate', matrix=[[1, 0], [0, 'exp(1j*lam)']])
factory.u2_factory = GateFactory(name='U2Gate', matrix=[[0.7071067811865475, '-exp(1j*lam) / sqrt(2)'], ['exp(1j*phi) / sqrt(2)', 'exp(1j*(phi + lam)) / sqrt(2)']])
factory.u3_factory = GateFactory(name='U3Gate', matrix=[['cos(theta / 2)', '-exp(1j*lam) * sin(theta / 2)'], ['exp(1j*phi) * sin(theta / 2)', 'exp(1j*(phi + lam)) * cos(theta / 2)']])
factory.phasedXPow_factory = GateFactory(name='PhasedXPow', matrix=[['cos(theta / 2 * pi)', '-1j * exp(-1j*lam * pi) * sin(theta / 2 * pi)'], ['-1j * exp(1j*lam * pi) * sin(theta / 2 * pi)', 'cos(theta / 2 * pi)']])
factory.ms_factory = GateFactory(name='MS', hamiltonian=[['XX', 'theta']])
factory.fsim_factory = GateFactory(name='FSim', matrix=[[1, 0, 0, 0], [0, 'cos(theta * pi / 180)', '-1j*sin(theta * pi / 180)', 0], [0, '-1j*sin(theta * pi / 180)', 'cos(theta * pi / 180)', 0], [0, 0, 0, 'exp(1j * phi * pi / 180)']])