Skip to content

Serialization

Serialization

deserialize(d, as_torch=False)

Supported Types:

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

PARAMETER DESCRIPTION
d

A dict containing a serialized object.

TYPE: dict

as_torch

Whether to transform to torch for the deserialized object.

TYPE: bool DEFAULT: False

Returns: AbstractBlock, QuantumCircuit, QuantumModel, Register, torch.nn.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': ('b88ab148-d412-4fd2-9463-bef06a0612d8', {'name': 'theta_0', 'expression': "Parameter('theta_0')", 'symbols': {'theta_0': {'name': 'theta_0', 'trainable': 'True', 'value': '0.3161299695139759'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('3743d0a5-8e67-4ac9-a946-71fe14ce9a45', {'name': 'theta_1', 'expression': "Parameter('theta_1')", 'symbols': {'theta_1': {'name': 'theta_1', 'trainable': 'True', 'value': '0.5384353967033657'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RY', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('a2f99d1b-4f27-4f63-b2da-541d2f4dd401', {'name': 'theta_2', 'expression': "Parameter('theta_2')", 'symbols': {'theta_2': {'name': 'theta_2', 'trainable': 'True', 'value': '0.6582804446219259'}}})}}}, {'type': 'RY', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('3ca0711d-9e08-4c28-b096-e212b1a0c2e1', {'name': 'theta_3', 'expression': "Parameter('theta_3')", 'symbols': {'theta_3': {'name': 'theta_3', 'trainable': 'True', 'value': '0.15573217766879666'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('ac24bb98-d133-4161-bd54-9e7647dac660', {'name': 'theta_4', 'expression': "Parameter('theta_4')", 'symbols': {'theta_4': {'name': 'theta_4', 'trainable': 'True', 'value': '0.10163985747076443'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('26dacd0b-9c49-4d91-be9b-f47d928db70b', {'name': 'theta_5', 'expression': "Parameter('theta_5')", 'symbols': {'theta_5': {'name': 'theta_5', 'trainable': 'True', 'value': '0.5321367874111326'}}})}}}]}]}, {'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 | Register | torch.nn.Module
    Deserializes a dict to one of the supported types.

    Arguments:
        d (dict): A dict containing a serialized object.
        as_torch (bool): Whether to transform to torch for the deserialized object.
    Returns:
        AbstractBlock, QuantumCircuit, QuantumModel, Register, torch.nn.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: SerializationModel
    if d.get("expression"):
        obj = ExpressionSerialization(d)
    elif d.get("block") and d.get("register"):
        obj = QuantumCircuitSerialization(d)
    elif d.get("graph"):
        obj = RegisterSerialization(d)
    elif d.get("type"):
        obj = BlockTypeSerialization(d)
    else:
        obj = ModelSerialization(d, as_torch=as_torch)
    return obj.value

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:

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:

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 | torch.nn.Module | 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': ('7c71af92-089a-4314-9976-d7f28a3bae72', {'name': 'theta_0', 'expression': "Parameter('theta_0')", 'symbols': {'theta_0': {'name': 'theta_0', 'trainable': 'True', 'value': '0.361318912315175'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('4c0c947f-cca8-4ce6-a314-ff0c8ab436dc', {'name': 'theta_1', 'expression': "Parameter('theta_1')", 'symbols': {'theta_1': {'name': 'theta_1', 'trainable': 'True', 'value': '0.04228551486512799'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RY', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('16f6190d-af5d-4dbc-a972-d7cda8a994f3', {'name': 'theta_2', 'expression': "Parameter('theta_2')", 'symbols': {'theta_2': {'name': 'theta_2', 'trainable': 'True', 'value': '0.5168972306270965'}}})}}}, {'type': 'RY', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('1392842e-207f-4292-88dd-602c8cc660f5', {'name': 'theta_3', 'expression': "Parameter('theta_3')", 'symbols': {'theta_3': {'name': 'theta_3', 'trainable': 'True', 'value': '0.37621294167733776'}}})}}}]}, {'type': 'KronBlock', 'qubit_support': (0, 1), 'tag': None, 'blocks': [{'type': 'RX', 'qubit_support': (0,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('ea1736a7-32e5-467c-894e-848ab522280d', {'name': 'theta_4', 'expression': "Parameter('theta_4')", 'symbols': {'theta_4': {'name': 'theta_4', 'trainable': 'True', 'value': '0.9637295823379295'}}})}}}, {'type': 'RX', 'qubit_support': (1,), 'tag': None, 'parameters': {'_name_dict': {'parameter': ('08bf1b70-131b-443c-acaf-65734feadc4b', {'name': 'theta_5', 'expression': "Parameter('theta_5')", 'symbols': {'theta_5': {'name': 'theta_5', 'trainable': 'True', 'value': '0.382974166158201'}}})}}}]}]}, {'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 | torch.nn.Module | Register | Module
    Serializes a qadence object to a dictionary.

    Arguments:
        obj (AbstractBlock | QuantumCircuit | QuantumModel | Register | torch.nn.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 = dict()
    try:
        if isinstance(obj, core.Expr):
            symb_dict = dict()
            expr_dict = {"name": str(obj), "expression": srepr(obj)}
            symbs: set[Parameter | core.Basic] = obj.free_symbols
            if symbs:
                symb_dict = {"symbols": {str(s): s._to_dict() for s in symbs}}
            d = {**expr_dict, **symb_dict}
        else:
            if hasattr(obj, "_to_dict"):
                model_to_dict: Callable = obj._to_dict
                d = (
                    model_to_dict(save_params)
                    if isinstance(obj, torch.nn.Module)
                    else model_to_dict()
                )
            elif hasattr(obj, "state_dict"):
                d = {type(obj).__name__: obj.state_dict()}
            else:
                raise ValueError(f"Cannot serialize object {obj}.")
    except Exception as e:
        logger.error(f"Serialization of object {obj} failed due to {e}")
    return d