Skip to content

Serialization

Serialization

deserialize(d, as_torch=False)

Supported Types:

AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module Deserializes a dict to one of the supported types.

PARAMETER DESCRIPTION
d

A dict containing a serialized object.

TYPE: dict

Returns: AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register, Module.

Examples:

import torch
from qadence import serialize, deserialize, hea, hamiltonian_factory, Z
from qadence import QuantumCircuit, QuantumModel

n_qubits = 2
myblock = hea(n_qubits=n_qubits, depth=1)
block_dict = serialize(myblock)
print(block_dict)

## Lets use myblock in a QuantumCircuit and serialize it.

qc = QuantumCircuit(n_qubits, myblock)
qc_dict = serialize(qc)
qc_deserialized = deserialize(qc_dict)
assert qc == qc_deserialized

## Finally, let's wrap it in a QuantumModel
obs = hamiltonian_factory(n_qubits, detuning = Z)
qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')

qm_dict = serialize(qm)
qm_deserialized = deserialize(qm_dict)
# Lets check if the loaded QuantumModel returns the same expectation
assert torch.isclose(qm.expectation({}), qm_deserialized.expectation({}))
{'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': 'HEA', 'blocks': [{'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('f3125637-7fbf-46d1-a68a-09767260357f', {'name': 'theta_0', 'expression': "Parameter('theta_0')", 'symbols': {'theta_0': {'name': 'theta_0', 'trainable': 'True', 'value': '0.6398639069137206'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('d3827f14-62ac-4246-b147-9ba65776a315', {'name': 'theta_1', 'expression': "Parameter('theta_1')", 'symbols': {'theta_1': {'name': 'theta_1', 'trainable': 'True', 'value': '0.4276945815961849'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RY', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('26309b3d-1e2d-4264-8d72-6957fdf0137b', {'name': 'theta_2', 'expression': "Parameter('theta_2')", 'symbols': {'theta_2': {'name': 'theta_2', 'trainable': 'True', 'value': '0.8742892845567309'}}})}}}, {'type': 'RY', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('7c550f44-4be3-484d-8a2e-d06a895220a6', {'name': 'theta_3', 'expression': "Parameter('theta_3')", 'symbols': {'theta_3': {'name': 'theta_3', 'trainable': 'True', 'value': '0.41919975377010965'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('1b1c5438-fd51-40a9-b94a-a258e8705a30', {'name': 'theta_4', 'expression': "Parameter('theta_4')", 'symbols': {'theta_4': {'name': 'theta_4', 'trainable': 'True', 'value': '0.6109177287180888'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('626a58ec-c67b-4d2f-8749-c0db6e8d328c', {'name': 'theta_5', 'expression': "Parameter('theta_5')", 'symbols': {'theta_5': {'name': 'theta_5', 'trainable': 'True', 'value': '0.37421788716051174'}}})}}}]}]}, {'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'CNOT', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'X', 'qubit_support': (1,), 'tag': None}]}]}]}]}

Source code in qadence/serialization.py
def deserialize(d: dict, as_torch: bool = False) -> SUPPORTED_TYPES:
    """
    Supported Types:

    AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module
    Deserializes a dict to one of the supported types.

    Arguments:
        d (dict): A dict containing a serialized object.
    Returns:
        AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register, Module.

    Examples:
    ```python exec="on" source="material-block" result="json"
    import torch
    from qadence import serialize, deserialize, hea, hamiltonian_factory, Z
    from qadence import QuantumCircuit, QuantumModel

    n_qubits = 2
    myblock = hea(n_qubits=n_qubits, depth=1)
    block_dict = serialize(myblock)
    print(block_dict)

    ## Lets use myblock in a QuantumCircuit and serialize it.

    qc = QuantumCircuit(n_qubits, myblock)
    qc_dict = serialize(qc)
    qc_deserialized = deserialize(qc_dict)
    assert qc == qc_deserialized

    ## Finally, let's wrap it in a QuantumModel
    obs = hamiltonian_factory(n_qubits, detuning = Z)
    qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')

    qm_dict = serialize(qm)
    qm_deserialized = deserialize(qm_dict)
    # Lets check if the loaded QuantumModel returns the same expectation
    assert torch.isclose(qm.expectation({}), qm_deserialized.expectation({}))
    ```
    """
    obj: Any
    if d.get("expression"):
        expr = eval(d["expression"])
        if hasattr(expr, "free_symbols"):
            for symb in expr.free_symbols:
                symb.value = float(d["symbols"][symb.name]["value"])
        obj = expr
    elif d.get("QuantumModel"):
        obj = QuantumModel._from_dict(d, as_torch)
    elif d.get("QNN"):
        obj = QNN._from_dict(d, as_torch)
    elif d.get("TransformedModule"):
        obj = TransformedModule._from_dict(d, as_torch)
    elif d.get("block") and d.get("register"):
        obj = QuantumCircuit._from_dict(d)
    elif d.get("graph"):
        obj = Register._from_dict(d)
    elif d.get("type"):
        if d["type"] in ALL_BLOCK_NAMES:
            block: AbstractBlock = (
                getattr(operations, d["type"])._from_dict(d)
                if hasattr(operations, d["type"])
                else getattr(qadenceblocks, d["type"])._from_dict(d)
            )
            if d["tag"] is not None:
                block = tag(block, d["tag"])
            obj = block
    else:
        import warnings

        msg = warnings.warn(
            "In order to load a custom torch.nn.Module, make sure its imported in the namespace."
        )
        try:
            module_name = list(d.keys())[0]
            obj = getattr(globals(), module_name)
            obj.load_state_dict(d[module_name])
        except Exception as e:
            logger.error(
                TypeError(
                    f"{msg}. Unable to deserialize object due to {e}.\
                    Supported objects are: {SUPPORTED_OBJECTS}"
                )
            )
    return obj

load(file_path, map_location='cpu')

Same as serialize/deserialize but for storing/loading files.

Supported types: AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register Loads a .json or .pt file to one of the supported types.

PARAMETER DESCRIPTION
file_path

The name of the file.

TYPE: str

map_location

In case of a .pt file, on which device to load the object (cpu,cuda).

TYPE: str DEFAULT: 'cpu'

Returns: A object of type AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register.

Examples:

import torch
from pathlib import Path
import os

from qadence import save, load, hea, hamiltonian_factory, Z
from qadence import QuantumCircuit, QuantumModel

n_qubits = 2
myblock = hea(n_qubits=n_qubits, depth=1)
qc = QuantumCircuit(n_qubits, myblock)
# Lets store the circuit in a json file
save(qc, '.', 'circ')
loaded_qc = load(Path('circ.json'))
qc == loaded_qc
os.remove('circ.json')
## Let's wrap it in a QuantumModel and store that
obs = hamiltonian_factory(n_qubits, detuning = Z)
qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')
save(qm, folder= '.',file_name= 'quantum_model')
qm_loaded = load('quantum_model.json')
os.remove('quantum_model.json')

Source code in qadence/serialization.py
def load(file_path: str | Path, map_location: str = "cpu") -> SUPPORTED_TYPES:
    """
    Same as serialize/deserialize but for storing/loading files.

    Supported types: AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register
    Loads a .json or .pt file to one of the supported types.

    Arguments:
        file_path (str): The name of the file.
        map_location (str): In case of a .pt file, on which device to load the object (cpu,cuda).
    Returns:
        A object of type AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register.

    Examples:
    ```python exec="on" source="material-block" result="json"
    import torch
    from pathlib import Path
    import os

    from qadence import save, load, hea, hamiltonian_factory, Z
    from qadence import QuantumCircuit, QuantumModel

    n_qubits = 2
    myblock = hea(n_qubits=n_qubits, depth=1)
    qc = QuantumCircuit(n_qubits, myblock)
    # Lets store the circuit in a json file
    save(qc, '.', 'circ')
    loaded_qc = load(Path('circ.json'))
    qc == loaded_qc
    os.remove('circ.json')
    ## Let's wrap it in a QuantumModel and store that
    obs = hamiltonian_factory(n_qubits, detuning = Z)
    qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')
    save(qm, folder= '.',file_name= 'quantum_model')
    qm_loaded = load('quantum_model.json')
    os.remove('quantum_model.json')
    ```
    """
    d = {}
    if isinstance(file_path, str):
        file_path = Path(file_path)
    if not os.path.exists(file_path):
        logger.error(f"File {file_path} not found.")
        raise FileNotFoundError
    FORMAT = file_extension(file_path)
    _, _, load_fn, _ = FORMAT_DICT[FORMAT]  # type: ignore[index]
    try:
        d = load_fn(file_path, map_location)
        logger.debug(f"Successfully loaded {d} from {file_path}.")
    except Exception as e:
        logger.error(f"Unable to load Object from {file_path} due to {e}")
    return deserialize(d)

save(obj, folder, file_name='', format=SerializationFormat.JSON)

Same as serialize/deserialize but for storing/loading files.

Supported types: AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | torch.nn.Module Saves a qadence object to a json/.pt.

PARAMETER DESCRIPTION
obj
Either AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register.

TYPE: AbstractBlock | QuantumCircuit | QuantumModel | Register

file_name

The name of the file.

TYPE: str DEFAULT: ''

format

The type of file to save.

TYPE: str DEFAULT: JSON

Returns: None.

Examples:

import torch
from pathlib import Path
import os

from qadence import save, load, hea, hamiltonian_factory, Z
from qadence import QuantumCircuit, QuantumModel

n_qubits = 2
myblock = hea(n_qubits=n_qubits, depth=1)
qc = QuantumCircuit(n_qubits, myblock)
# Lets store the circuit in a json file
save(qc, '.', 'circ')
loaded_qc = load(Path('circ.json'))
qc == loaded_qc
os.remove('circ.json')
## Let's wrap it in a QuantumModel and store that
obs = hamiltonian_factory(n_qubits, detuning = Z)
qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')
save(qm, folder= '.',file_name= 'quantum_model')
qm_loaded = load('quantum_model.json')
os.remove('quantum_model.json')

Source code in qadence/serialization.py
def save(
    obj: SUPPORTED_TYPES,
    folder: str | Path,
    file_name: str = "",
    format: SerializationFormat = SerializationFormat.JSON,
) -> None:
    """
    Same as serialize/deserialize but for storing/loading files.

    Supported types:
    AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | torch.nn.Module
    Saves a qadence object to a json/.pt.

    Arguments:
        obj (AbstractBlock | QuantumCircuit | QuantumModel | Register):
                Either AbstractBlock, QuantumCircuit, QuantumModel, TransformedModule, Register.
        file_name (str): The name of the file.
        format (str): The type of file to save.
    Returns:
        None.

    Examples:
    ```python exec="on" source="material-block" result="json"
    import torch
    from pathlib import Path
    import os

    from qadence import save, load, hea, hamiltonian_factory, Z
    from qadence import QuantumCircuit, QuantumModel

    n_qubits = 2
    myblock = hea(n_qubits=n_qubits, depth=1)
    qc = QuantumCircuit(n_qubits, myblock)
    # Lets store the circuit in a json file
    save(qc, '.', 'circ')
    loaded_qc = load(Path('circ.json'))
    qc == loaded_qc
    os.remove('circ.json')
    ## Let's wrap it in a QuantumModel and store that
    obs = hamiltonian_factory(n_qubits, detuning = Z)
    qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')
    save(qm, folder= '.',file_name= 'quantum_model')
    qm_loaded = load('quantum_model.json')
    os.remove('quantum_model.json')
    ```
    """
    if not isinstance(obj, get_args(SUPPORTED_TYPES)):
        logger.error(f"Serialization of object type {type(obj)} not supported.")
    folder = Path(folder)
    if not folder.is_dir():
        logger.error(NotADirectoryError)
    if file_name == "":
        file_name = type(obj).__name__
    try:
        suffix, save_fn, _, save_params = FORMAT_DICT[format]
        d = serialize(obj, save_params)
        file_path = folder / Path(file_name + suffix)
        save_fn(d, file_path)
        logger.debug(f"Successfully saved {obj} from to {folder}.")
    except Exception as e:
        logger.error(f"Unable to write {type(obj)} to disk due to {e}")

serialize(obj, save_params=False)

Supported Types:

AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module Serializes a qadence object to a dictionary.

PARAMETER DESCRIPTION
obj

TYPE: AbstractBlock | QuantumCircuit | QuantumModel | Register | Module

Returns: A dict.

Examples:

import torch
from qadence import serialize, deserialize, hea, hamiltonian_factory, Z
from qadence import QuantumCircuit, QuantumModel

n_qubits = 2
myblock = hea(n_qubits=n_qubits, depth=1)
block_dict = serialize(myblock)
print(block_dict)

## Lets use myblock in a QuantumCircuit and serialize it.

qc = QuantumCircuit(n_qubits, myblock)
qc_dict = serialize(qc)
qc_deserialized = deserialize(qc_dict)
assert qc == qc_deserialized

## Finally, let's wrap it in a QuantumModel
obs = hamiltonian_factory(n_qubits, detuning = Z)
qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')

qm_dict = serialize(qm)
qm_deserialized = deserialize(qm_dict)
# Lets check if the loaded QuantumModel returns the same expectation
assert torch.isclose(qm.expectation({}), qm_deserialized.expectation({}))
{'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': 'HEA', 'blocks': [{'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('b7624d07-8890-4046-bf00-d54c831fc546', {'name': 'theta_0', 'expression': "Parameter('theta_0')", 'symbols': {'theta_0': {'name': 'theta_0', 'trainable': 'True', 'value': '0.9806087614373826'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('c7e785d4-9ac3-45f3-ba09-e3adc6c3d69e', {'name': 'theta_1', 'expression': "Parameter('theta_1')", 'symbols': {'theta_1': {'name': 'theta_1', 'trainable': 'True', 'value': '0.1191298453974663'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RY', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('b503b8cf-53f3-4a40-aee2-14b7a6890aaf', {'name': 'theta_2', 'expression': "Parameter('theta_2')", 'symbols': {'theta_2': {'name': 'theta_2', 'trainable': 'True', 'value': '0.2908857259376022'}}})}}}, {'type': 'RY', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('f907a7a7-bf7f-4219-8567-6a3c729533c3', {'name': 'theta_3', 'expression': "Parameter('theta_3')", 'symbols': {'theta_3': {'name': 'theta_3', 'trainable': 'True', 'value': '0.43496561975352277'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('bc3810b6-0946-45e8-a937-b5fd465feef1', {'name': 'theta_4', 'expression': "Parameter('theta_4')", 'symbols': {'theta_4': {'name': 'theta_4', 'trainable': 'True', 'value': '0.13952221070351867'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('1bd0c8fc-5a43-413b-b03d-4ca936845606', {'name': 'theta_5', 'expression': "Parameter('theta_5')", 'symbols': {'theta_5': {'name': 'theta_5', 'trainable': 'True', 'value': '0.230873635340905'}}})}}}]}]}, {'type': 'ChainBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'CNOT', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'X', 'qubit_support': (1,), 'tag': None}]}]}]}]}

Source code in qadence/serialization.py
def serialize(obj: SUPPORTED_TYPES, save_params: bool = False) -> dict:
    """
    Supported Types:

    AbstractBlock | QuantumCircuit | QuantumModel | TransformedModule | Register | Module
    Serializes a qadence object to a dictionary.

    Arguments:
        obj (AbstractBlock | QuantumCircuit | QuantumModel | Register | Module):
    Returns:
        A dict.

    Examples:
    ```python exec="on" source="material-block" result="json"
    import torch
    from qadence import serialize, deserialize, hea, hamiltonian_factory, Z
    from qadence import QuantumCircuit, QuantumModel

    n_qubits = 2
    myblock = hea(n_qubits=n_qubits, depth=1)
    block_dict = serialize(myblock)
    print(block_dict)

    ## Lets use myblock in a QuantumCircuit and serialize it.

    qc = QuantumCircuit(n_qubits, myblock)
    qc_dict = serialize(qc)
    qc_deserialized = deserialize(qc_dict)
    assert qc == qc_deserialized

    ## Finally, let's wrap it in a QuantumModel
    obs = hamiltonian_factory(n_qubits, detuning = Z)
    qm = QuantumModel(qc, obs, backend='pyqtorch', diff_mode='ad')

    qm_dict = serialize(qm)
    qm_deserialized = deserialize(qm_dict)
    # Lets check if the loaded QuantumModel returns the same expectation
    assert torch.isclose(qm.expectation({}), qm_deserialized.expectation({}))
    ```
    """
    if not isinstance(obj, get_args(SUPPORTED_TYPES)):
        logger.error(TypeError(f"Serialization of object type {type(obj)} not supported."))
    d: dict = {}
    try:
        if isinstance(obj, Expr):
            symb_dict = {}
            expr_dict = {"name": str(obj), "expression": srepr(obj)}
            symbs: set[Parameter | Basic] = obj.free_symbols
            if symbs:
                symb_dict = {"symbols": {str(s): s._to_dict() for s in symbs}}
            d = {**expr_dict, **symb_dict}
        elif isinstance(obj, (QuantumModel, QNN, TransformedModule)):
            d = obj._to_dict(save_params)
        elif isinstance(obj, torch.nn.Module):
            d = {type(obj).__name__: obj.state_dict()}
        else:
            d = obj._to_dict()
    except Exception as e:
        logger.error(f"Serialization of object {obj} failed due to {e}")
    return d