Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename subsystem_dims of Dict to subsystem_dims_dict #250

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,12 @@ def parse_backend_hamiltonian_dict(
# force keys in hamiltonian['qub'] to be ints
qub_dict = {int(key): val for key, val in hamiltonian_dict["qub"].items()}

subsystem_dims = {int(qubit): qub_dict[int(qubit)] for qubit in subsystem_list}
subsystem_dims_dict = {int(qubit): qub_dict[int(qubit)] for qubit in subsystem_list}

# Parse the Hamiltonian
system = _regex_parser(
operator_str=hamiltonian_dict["h_str"],
subsystem_dims=subsystem_dims,
subsystem_dims_dict=subsystem_dims_dict,
subsystem_list=subsystem_list,
)

Expand Down Expand Up @@ -227,7 +227,12 @@ def parse_backend_hamiltonian_dict(
*sorted(zip(reduced_channels, hamiltonian_operators))
)

return static_hamiltonian, list(hamiltonian_operators), list(reduced_channels), subsystem_dims
return (
static_hamiltonian,
list(hamiltonian_operators),
list(reduced_channels),
subsystem_dims_dict,
)


def _hamiltonian_pre_parse_exceptions(hamiltonian_dict: dict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@


def _operator_from_string(
op_label: str, subsystem_label: int, subsystem_dims: Dict[int, int]
op_label: str, subsystem_label: int, subsystem_dims_dict: Dict[int, int]
) -> np.ndarray:
r"""Generates a dense operator acting on a single subsystem, tensoring
identities for remaining subsystems.

The single system operator is specified via a string in ``op_label``,
the list of subsystems and their corresponding dimensions are specified in the
dictionary ``subsystem_dims``, with system label being the keys specified as ``int``s,
dictionary ``subsystem_dims_dict``, with system label being the keys specified as ``int``s,
and system dimensions the values also specified as ``int``s, and ``subsystem_label``
indicates which subsystem the operator specified by ``op_label`` acts on.

Expand Down Expand Up @@ -61,7 +61,7 @@ def _operator_from_string(
Args:
op_label: The string labelling the single system operator.
subsystem_label: Index of the subsystem to apply the operator.
subsystem_dims: Dictionary of subsystem labels and dimensions.
subsystem_dims_dict: Dictionary of subsystem labels and dimensions.

Returns:
np.ndarray corresponding to the specified operator.
Expand All @@ -75,12 +75,12 @@ def _operator_from_string(
if op_func is None:
raise QiskitError(f"String {op_label} does not correspond to a known operator.")

dim = subsystem_dims[subsystem_label]
dim = subsystem_dims_dict[subsystem_label]
out = qi.Operator(op_func(dim), input_dims=[dim], output_dims=[dim])

# sort subsystem labels and dimensions according to subsystem label
sorted_subsystem_keys, sorted_subsystem_dims = zip(
*sorted(zip(subsystem_dims.keys(), subsystem_dims.values()))
*sorted(zip(subsystem_dims_dict.keys(), subsystem_dims_dict.values()))
)

# get subsystem location in ordered list
Expand Down
18 changes: 10 additions & 8 deletions qiskit_dynamics/backend/backend_string_parser/regex_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@


def _regex_parser(
operator_str: List[str], subsystem_dims: Dict[int, int], subsystem_list: List[int]
operator_str: List[str], subsystem_dims_dict: Dict[int, int], subsystem_list: List[int]
) -> List[Tuple[np.array, str]]:
"""Function wrapper for regex parsing object.

Args:
operator_str: List of strings in accepted format as described in
string_model_parser.parse_hamiltonian_dict.
subsystem_dims: Dictionary mapping subsystem labels to dimensions.
subsystem_dims_dict: Dictionary mapping subsystem labels to dimensions.
subsystem_list: List of subsystems on which the operators are to be constructed.
Returns:
List of tuples containing pairs operators and their string coefficients.
"""

return _HamiltonianParser(h_str=operator_str, subsystem_dims=subsystem_dims).parse(
return _HamiltonianParser(h_str=operator_str, subsystem_dims_dict=subsystem_dims_dict).parse(
subsystem_list
)

Expand All @@ -66,15 +66,17 @@ class _HamiltonianParser:
BrkR=re.compile(r"\)"),
)

def __init__(self, h_str, subsystem_dims):
def __init__(self, h_str, subsystem_dims_dict):
"""Create new quantum operator generator

Parameters:
h_str (list): list of Hamiltonian string
subsystem_dims (dict): dimension of subsystems
subsystem_dims_dict (dict): dimension of subsystems
"""
self.h_str = h_str
self.subsystem_dims = {int(label): int(dim) for label, dim in subsystem_dims.items()}
self.subsystem_dims_dict = {
int(label): int(dim) for label, dim in subsystem_dims_dict.items()
}
self.str2qopr = {}

def parse(self, qubit_list=None):
Expand Down Expand Up @@ -194,15 +196,15 @@ def _tokenizer(self, op_str, qubit_list=None):
if qubit_list is not None and idx not in qubit_list:
return 0, None
name = p.group("opr")
opr = _operator_from_string(name, idx, self.subsystem_dims)
opr = _operator_from_string(name, idx, self.subsystem_dims_dict)
self.str2qopr[p.group()] = opr
elif key == "PrjOpr":
_key = key
_name = p.group()
if p.group() not in self.str2qopr:
idx = int(p.group("idx"))
name = "P"
opr = _operator_from_string(name, idx, self.subsystem_dims)
opr = _operator_from_string(name, idx, self.subsystem_dims_dict)
self.str2qopr[p.group()] = opr
elif key in ["Func", "Ext"]:
_name = p.group("name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,13 @@ def test_only_static_terms(self):
"""Test a basic system."""
ham_dict = {"h_str": ["v*np.pi*Z0"], "qub": {"0": 2}, "vars": {"v": 2.1}}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)
self.assertAllClose(static_ham, 2.1 * np.pi * self.Z)
self.assertTrue(not ham_ops)
self.assertTrue(not channels)
self.assertTrue(subsystem_dims == {0: 2})
self.assertTrue(subsystem_dims_dict == {0: 2})

def test_simple_single_q_system(self):
"""Test a basic system."""
Expand All @@ -137,12 +139,14 @@ def test_simple_single_q_system(self):
"vars": {"v": 2.1},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

self.assertAllClose(static_ham, 2.1 * np.pi * self.Z)
self.assertAllClose(to_array(ham_ops), [0.02 * np.pi * self.X])
self.assertTrue(channels == ["d0"])
self.assertTrue(subsystem_dims == {0: 2})
self.assertTrue(subsystem_dims_dict == {0: 2})

def test_simple_single_q_system_repeat_entries(self):
"""Test merging of terms with same channel or no channel."""
Expand All @@ -152,12 +156,14 @@ def test_simple_single_q_system_repeat_entries(self):
"vars": {"v": 2.1},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

self.assertAllClose(static_ham, 2 * 2.1 * np.pi * self.Z)
self.assertAllClose(to_array(ham_ops), [2 * 0.02 * np.pi * self.X])
self.assertTrue(channels == ["d0"])
self.assertTrue(subsystem_dims == {0: 2})
self.assertTrue(subsystem_dims_dict == {0: 2})

def test_simple_single_q_system_repeat_entries_different_case(self):
"""Test merging of terms with same channel or no channel,
Expand All @@ -169,12 +175,14 @@ def test_simple_single_q_system_repeat_entries_different_case(self):
"vars": {"v": 2.1},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

self.assertAllClose(static_ham, 2 * 2.1 * np.pi * self.Z)
self.assertAllClose(to_array(ham_ops), [2 * 0.02 * np.pi * self.X])
self.assertTrue(channels == ["d0"])
self.assertTrue(subsystem_dims == {0: 2})
self.assertTrue(subsystem_dims_dict == {0: 2})

def test_simple_two_q_system(self):
"""Test a two qubit system."""
Expand All @@ -191,7 +199,9 @@ def test_simple_two_q_system(self):
"vars": {"v0": 2.1, "v1": 2.0, "j": 0.02},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

ident = np.eye(2)
self.assertAllClose(
Expand All @@ -205,7 +215,7 @@ def test_simple_two_q_system(self):
[0.02 * np.pi * np.kron(ident, self.X), 0.03 * np.pi * np.kron(self.X, ident)],
)
self.assertTrue(channels == ["d0", "d1"])
self.assertTrue(subsystem_dims == {0: 2, 1: 2})
self.assertTrue(subsystem_dims_dict == {0: 2, 1: 2})

def test_simple_two_q_system_measurement_channel(self):
"""Test a two qubit system with a measurement-labelled channel."""
Expand All @@ -222,7 +232,9 @@ def test_simple_two_q_system_measurement_channel(self):
"vars": {"v0": 2.1, "v1": 2.0, "j": 0.02},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

ident = np.eye(2)
self.assertAllClose(
Expand All @@ -236,7 +248,7 @@ def test_simple_two_q_system_measurement_channel(self):
[0.02 * np.pi * np.kron(ident, self.X), 0.03 * np.pi * np.kron(self.X, ident)],
)
self.assertTrue(channels == ["d0", "m1"])
self.assertTrue(subsystem_dims == {0: 2, 1: 2})
self.assertTrue(subsystem_dims_dict == {0: 2, 1: 2})

def test_single_oscillator_system(self):
"""Test single oscillator system."""
Expand All @@ -247,12 +259,14 @@ def test_single_oscillator_system(self):
"vars": {"v": 2.1, "alpha": -0.33, "r": 0.02},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

self.assertAllClose(static_ham, 2.1 * np.pi * self.N - 0.33 * np.pi * self.N * self.N)
self.assertAllClose(to_array(ham_ops), [0.02 * np.pi * (self.a + self.adag)])
self.assertTrue(channels == ["d0"])
self.assertTrue(subsystem_dims == {0: 4})
self.assertTrue(subsystem_dims_dict == {0: 4})

def test_two_oscillator_system(self):
"""Test a two qubit system."""
Expand All @@ -271,7 +285,9 @@ def test_two_oscillator_system(self):
"vars": {"v0": 2.1, "v1": 2.0, "alpha0": -0.33, "alpha1": -0.33, "j": 0.02},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

ident = np.eye(4)

Expand All @@ -291,7 +307,7 @@ def test_two_oscillator_system(self):
],
)
self.assertTrue(channels == ["d0", "d1"])
self.assertTrue(subsystem_dims == {0: 4, 1: 4})
self.assertTrue(subsystem_dims_dict == {0: 4, 1: 4})

def test_single_q_high_dim(self):
"""Test single q system but higher dim."""
Expand All @@ -301,12 +317,14 @@ def test_single_q_high_dim(self):
"vars": {"v": 2.1},
}

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(ham_dict)
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict
)

self.assertAllClose(static_ham, 2.1 * np.pi * (np.eye(4) - 2 * self.N))
self.assertAllClose(to_array(ham_ops), [0.02 * np.pi * (self.a + self.adag)])
self.assertTrue(channels == ["d0"])
self.assertTrue(subsystem_dims == {0: 4})
self.assertTrue(subsystem_dims_dict == {0: 4})

def test_dagger(self):
"""Test correct parsing of dagger."""
Expand Down Expand Up @@ -397,13 +415,13 @@ def test_5q_hamiltonian_reduced(self):
)
channels_expected = ["d0", "d1", "u0", "u1", "u2"]

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict, subsystem_list=[0, 1]
)
self.assertAllClose(static_ham, static_ham_expected)
self.assertAllClose(ham_ops, ham_ops_expected)
self.assertTrue(channels == channels_expected)
self.assertTrue(subsystem_dims == {0: 4, 1: 4})
self.assertTrue(subsystem_dims_dict == {0: 4, 1: 4})

# test case for subsystems [3, 4]

Expand All @@ -427,10 +445,10 @@ def test_5q_hamiltonian_reduced(self):
)
channels_expected = ["d3", "d4", "u5", "u6", "u7"]

static_ham, ham_ops, channels, subsystem_dims = parse_backend_hamiltonian_dict(
static_ham, ham_ops, channels, subsystem_dims_dict = parse_backend_hamiltonian_dict(
ham_dict, subsystem_list=[3, 4]
)
self.assertAllClose(static_ham, static_ham_expected)
self.assertAllClose(ham_ops, ham_ops_expected)
self.assertTrue(channels == channels_expected)
self.assertTrue(subsystem_dims == {3: 4, 4: 4})
self.assertTrue(subsystem_dims_dict == {3: 4, 4: 4})