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

Migrating Marek's code for DBI to discontinue the old repository #1143

Merged
merged 55 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
be3c3a2
Added files, successful canonical iterations.
Sam-XiaoyueLi Nov 28, 2023
af58414
Updates of names: flow->DBI, flowed->iterated
Sam-XiaoyueLi Nov 29, 2023
2ba60f7
Setup plot visualization: a)cost, b)initial matrix, c)final matrix
Sam-XiaoyueLi Nov 29, 2023
49e80cc
Deleted unused comments
Sam-XiaoyueLi Nov 29, 2023
3f4e0c0
Structure for best Zsearch
Sam-XiaoyueLi Nov 29, 2023
77b3389
Remove redundant H input
Sam-XiaoyueLi Nov 30, 2023
e334213
Update dependency: seaborn
Sam-XiaoyueLi Nov 30, 2023
25854b9
Fix lint errors
Sam-XiaoyueLi Dec 4, 2023
81f4f53
Iteration from list, most changes contained in additional file
Sam-XiaoyueLi Dec 18, 2023
fc0b64b
Added description in example notebook, deleted redundant notebook
Sam-XiaoyueLi Dec 20, 2023
6cf4a96
Fixed example code, added documentation
Sam-XiaoyueLi Dec 20, 2023
1c6d6ca
added test codes
Sam-XiaoyueLi Dec 20, 2023
5222045
Added missed arguments changes
Sam-XiaoyueLi Dec 20, 2023
9913226
Rename notebooks, added mixed strategy tests and fixed minor issue wi…
Sam-XiaoyueLi Dec 20, 2023
9c4956b
Merge remote-tracking branch 'origin/HEAD' into dbf_migrate
Sam-XiaoyueLi Dec 21, 2023
d75b357
Resolved issue for functools.partial, reason for previous error uncle…
Sam-XiaoyueLi Jan 5, 2024
2085c3d
1. Simplify generate_Z_operators function with added function str_to_op
Sam-XiaoyueLi Jan 5, 2024
3ecdd2e
1. Renamed additional functions into utils.py
Sam-XiaoyueLi Jan 5, 2024
1b29ccd
Remove redundant dependencies
Sam-XiaoyueLi Jan 5, 2024
7503a01
Added descriptions in notebooks, clean outputs.
Sam-XiaoyueLi Jan 5, 2024
540c7a7
Modify descriptions and NSTEPS for better presentation
Sam-XiaoyueLi Jan 5, 2024
a9539c9
Set hyperopt max_evals=200 (notebook 300)
Sam-XiaoyueLi Jan 5, 2024
604f14e
use diagonal matrix with group commutator
Edoardo-Pedicillo Jan 10, 2024
bdbc073
Deleted code comments; fix example code snippet
Sam-XiaoyueLi Jan 11, 2024
d985db4
Added doc string to str_to_op (changed name to str_to_symbolic to be …
Sam-XiaoyueLi Jan 11, 2024
be96068
Added test file
Sam-XiaoyueLi Jan 15, 2024
02eb2b6
Formatting
Sam-XiaoyueLi Jan 15, 2024
8cc7e0d
Rename symbol
Sam-XiaoyueLi Jan 15, 2024
759ae7b
Merge pull request #1154 from qiboteam/dbi_fix
MatteoRobbiati Jan 17, 2024
41bc42a
Fix error with Pauli-Z, added sign flip
Sam-XiaoyueLi Jan 17, 2024
5634830
Fixed test codes according to previous change
Sam-XiaoyueLi Jan 17, 2024
312df2f
Remove valueerror from test for single commutator
Sam-XiaoyueLi Jan 24, 2024
59185dc
Remove select_best_dbr_and_run
Sam-XiaoyueLi Jan 24, 2024
d01b48a
Update test file for utils.py
Sam-XiaoyueLi Jan 24, 2024
10eb087
Clear notebook outputs
Sam-XiaoyueLi Jan 24, 2024
33a19a5
test: Fix coverage
andrea-pasquale Jan 24, 2024
7d9ecaf
Solve missing line 70 in test_models_dbi.py, added line dbi call with…
Sam-XiaoyueLi Jan 25, 2024
23844ab
Fix doc string error: off_diagonal_norm: latex missing \Tr
Sam-XiaoyueLi Jan 29, 2024
2650243
Fixed error with select_best_dbr_generator: initial off-norm list mus…
Sam-XiaoyueLi Jan 29, 2024
a4ebd8b
Merge branch 'dbf_migrate' into fix_dbi_tests
andrea-pasquale Jan 30, 2024
f32dd5f
Merge pull request #1164 from qiboteam/fix_dbi_tests
Sam-XiaoyueLi Jan 31, 2024
24d7b66
Merge branch 'master' into dbf_migrate
renatomello Feb 2, 2024
0d15274
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 2, 2024
b40b137
Merge branch 'master' into dbf_migrate
renatomello Feb 3, 2024
4f148b8
Lower case PEP 8 convention Update src/qibo/models/dbi/utils.py
marekgluza Feb 5, 2024
2fb84d4
Update name change in
Sam-XiaoyueLi Feb 13, 2024
138e133
Apply suggestions from code review
MatteoRobbiati Feb 13, 2024
056830f
Update tests/test_models_dbi_utils.py
MatteoRobbiati Feb 13, 2024
d994b4a
argmin + renamed variable
MatteoRobbiati Feb 19, 2024
d2d678c
complete sentence in docstrings
MatteoRobbiati Feb 19, 2024
d1d242e
rm mode since not used
MatteoRobbiati Feb 19, 2024
677d2d5
lightening tests
MatteoRobbiati Feb 19, 2024
18f70c3
Update src/qibo/models/dbi/double_bracket.py
MatteoRobbiati Feb 19, 2024
0ff852b
rm unused imports
MatteoRobbiati Feb 19, 2024
f84ca33
Merge branch 'master' into dbf_migrate
andrea-pasquale Feb 23, 2024
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
542 changes: 542 additions & 0 deletions examples/dbi/DBI_strategy_Pauli-Z_products.ipynb
Sam-XiaoyueLi marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

764 changes: 0 additions & 764 deletions examples/dbi/dbi.ipynb

This file was deleted.

562 changes: 562 additions & 0 deletions examples/dbi/dbi_tutorial_basic_intro.ipynb
Sam-XiaoyueLi marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file added src/qibo/models/dbi/__init__.py
Empty file.
28 changes: 14 additions & 14 deletions src/qibo/models/dbi/double_bracket.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import hyperopt
import numpy as np

from qibo.config import raise_error
from qibo.hamiltonians import Hamiltonian


Expand Down Expand Up @@ -33,13 +32,12 @@ class DoubleBracketIteration:
Example:
.. testcode::

import numpy as np
from qibo.models.dbi.double_bracket import DoubleBracketIteration, DoubleBracketGeneratorType
from qibo.hamiltonians import Hamiltonian
from qibo.quantum_info import random_hermitian
from qibo.hamiltonians import Hamiltonian

nqubits = 4
h0 = random_hermitian(2**nqubits)
h0 = random_hermitian(2**nqubits, seed=2)
dbf = DoubleBracketIteration(Hamiltonian(nqubits=nqubits, matrix=h0))

# diagonalized matrix
Expand Down Expand Up @@ -68,14 +66,14 @@ def __call__(
)
elif mode is DoubleBracketGeneratorType.single_commutator:
if d is None:
raise_error(ValueError, f"Cannot use group_commutator with matrix {d}")
d = self.diagonal_h_matrix
operator = self.backend.calculate_matrix_exp(
1.0j * step,
self.commutator(d, self.h.matrix),
)
elif mode is DoubleBracketGeneratorType.group_commutator:
if d is None:
raise_error(ValueError, f"Cannot use group_commutator with matrix {d}")
d = self.diagonal_h_matrix
operator = (
self.h.exp(-step)
@ self.backend.calculate_matrix_exp(-step, d)
Expand Down Expand Up @@ -103,12 +101,12 @@ def off_diag_h(self):

@property
def off_diagonal_norm(self):
"""Norm of off-diagonal part of H matrix."""
r"""Hilbert Schmidt norm of off-diagonal part of H matrix, namely :math:`\\text{Tr}(\\sqrt{A^{\\dagger} A})`."""
off_diag_h_dag = self.backend.cast(
np.matrix(self.backend.to_numpy(self.off_diag_h)).getH()
)
return np.real(
np.trace(self.backend.to_numpy(off_diag_h_dag @ self.off_diag_h))
return np.sqrt(
np.real(np.trace(self.backend.to_numpy(off_diag_h_dag @ self.off_diag_h)))
)

@property
Expand All @@ -125,6 +123,7 @@ def hyperopt_step(
optimizer: callable = None,
look_ahead: int = 1,
verbose: bool = False,
d: np.array = None,
):
"""
Optimize iteration step.
Expand All @@ -136,7 +135,8 @@ def hyperopt_step(
space: see hyperopt.hp possibilities;
optimizer: see hyperopt algorithms;
look_ahead: number of iteration steps to compute the loss function;
verbose: level of verbosity.
verbose: level of verbosity;
d: diagonal operator for generating double-bracket iterations.

Returns:
(float): optimized best iteration step.
Expand All @@ -148,28 +148,28 @@ def hyperopt_step(

space = space("step", step_min, step_max)
best = hyperopt.fmin(
fn=partial(self.loss, look_ahead=look_ahead),
fn=partial(self.loss, d=d, look_ahead=look_ahead),
space=space,
algo=optimizer.suggest,
max_evals=max_evals,
verbose=verbose,
)

return best["step"]

def loss(self, step: float, look_ahead: int = 1):
def loss(self, step: float, d: np.array = None, look_ahead: int = 1):
"""
Compute loss function distance between `look_ahead` steps.

Args:
step: iteration step.
d: diagonal operator, use canonical by default.
look_ahead: number of iteration steps to compute the loss function;
"""
# copy initial hamiltonian
h_copy = deepcopy(self.h)

for _ in range(look_ahead):
self.__call__(mode=self.mode, step=step)
self.__call__(mode=self.mode, step=step, d=d)

# off_diagonal_norm's value after the steps
loss = self.off_diagonal_norm
Expand Down
159 changes: 159 additions & 0 deletions src/qibo/models/dbi/utils.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add this utils function to the Qibo documentation.
I can do that just before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @MatteoRobbiati thanks that would be helpful! There's Chinese New Year now so we are both off next week but once @Sam-XiaoyueLi is back it would be great to close the PR! :)

Copy link
Contributor

@MatteoRobbiati MatteoRobbiati Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no problem. Another solution is that I go ahead with the modifications and ask @andrea-pasquale and @Edoardo-Pedicillo for a final review :) So that everything will be merged when you are back.

OFC if @Sam-XiaoyueLi you are ok with this. Otherwise we can simply wait until you are back!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would be fantastic if you could merge after your changes, thanks @MatteoRobbiati

if there are any issues, you can raise separate issues too and assign @Sam-XiaoyueLi and then we can split the requests into smaller merges. Will be easier to close the PRs? Happy CNY! :)

Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
from copy import deepcopy
from itertools import product
from typing import Optional

import numpy as np
from hyperopt import hp, tpe

from qibo import symbols
from qibo.hamiltonians import SymbolicHamiltonian
from qibo.models.dbi.double_bracket import (
DoubleBracketGeneratorType,
DoubleBracketIteration,
)


def generate_Z_operators(nqubits: int):
"""Generate a dictionary containing 1) all possible products of Pauli Z operators for L = n_qubits and 2) their respective names.
Sam-XiaoyueLi marked this conversation as resolved.
Show resolved Hide resolved
Return: Dictionary with operator names (str) as keys and operators (np.array) as values

Example:
.. testcode::

from qibo.models.dbi.utils import generate_Z_operators
from qibo.models.dbi.double_bracket import DoubleBracketIteration
from qibo.quantum_info import random_hermitian
from qibo.hamiltonians import Hamiltonian
import numpy as np

nqubits = 4
h0 = random_hermitian(2**nqubits)
dbi = DoubleBracketIteration(Hamiltonian(nqubits=nqubits, matrix=h0))
Sam-XiaoyueLi marked this conversation as resolved.
Show resolved Hide resolved
generate_Z = generate_Z_operators(nqubits)
Z_ops = list(generate_Z.values())

delta_h0 = dbi.diagonal_h_matrix
dephasing_channel = (sum([Z_op @ h0 @ Z_op for Z_op in Z_ops])+h0)/2**nqubits
norm_diff = np.linalg.norm(delta_h0 - dephasing_channel)
"""
# list of tuples, e.g. ('Z','I','Z')
combination_strings = product("ZI", repeat=nqubits)
output_dict = {}

for zi_string_combination in combination_strings:
# except for the identity
if "Z" in zi_string_combination:
op_name = "".join(zi_string_combination)
tensor_op = str_to_symbolic(op_name)
# append in output_dict
output_dict[op_name] = SymbolicHamiltonian(tensor_op).dense.matrix
return output_dict


def str_to_symbolic(name: str):
"""Convert string into symbolic hamiltonian.
Example:
.. testcode::

from qibo.models.dbi.utils import str_to_symbolic
op_name = "ZYXZI"
# returns 5-qubit symbolic hamiltonian
ZIXZI_op = str_to_symbolic(op_name)
"""
tensor_op = 1
for qubit, char in enumerate(name):
tensor_op *= getattr(symbols, char)(qubit)
return tensor_op


def select_best_dbr_generator(
Sam-XiaoyueLi marked this conversation as resolved.
Show resolved Hide resolved
dbi_object: DoubleBracketIteration,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MatteoRobbiati @Edoardo-Pedicillo if you agree, I believe that here it would make more sense to pass a hamiltonian as argument. The function should then return the correct DBI instance with the corresponding execution parameters d, step and so on...

d_list: list,
step: Optional[float] = None,
step_min: float = 1e-5,
step_max: float = 1,
max_evals: int = 200,
compare_canonical: bool = True,
):
"""Selects the best double bracket rotation generator from a list and execute the rotation.

Args:
dbi_object (`DoubleBracketIteration`): the target DoubleBracketIteration object.
d_list (list): list of diagonal operators (np.array) to run from.
step (float): fixed iteration duration.
Defaults to ``None``, uses hyperopt.
step_min (float): minimally allowed iteration duration.
step_max (float): maximally allowed iteration duration.
max_evals (int): maximally allowed number of evaluation in hyperopt.
compare_canonical (bool): if `True`, the optimal diagonal operator chosen from "d_list" is compared with the canonical bracket.

Returns:
The updated dbi_object, index of the optimal diagonal operator, respective step duration, and evolution direction.
"""
norms_off_diagonal_restriction = [
dbi_object.off_diagonal_norm for _ in range(len(d_list))
]
optimal_steps, flip_list = [], []
for i, d in enumerate(d_list):
# prescribed step durations
dbi_eval = deepcopy(dbi_object)
flip_list.append(cs_angle_sgn(dbi_eval, d))
if flip_list[i] != 0:
if step is None:
step_best = dbi_eval.hyperopt_step(
d=flip_list[i] * d,
step_min=step_min,
step_max=step_max,
space=hp.uniform,
optimizer=tpe,
max_evals=max_evals,
andrea-pasquale marked this conversation as resolved.
Show resolved Hide resolved
)
else:
step_best = step
dbi_eval(step=step_best, d=flip_list[i] * d)
optimal_steps.append(step_best)
norms_off_diagonal_restriction[i] = dbi_eval.off_diagonal_norm
# canonical
if compare_canonical is True:
flip_list.append(1)
dbi_eval = deepcopy(dbi_object)
dbi_eval.mode = DoubleBracketGeneratorType.canonical
if step is None:
step_best = dbi_eval.hyperopt_step(
step_min=step_min,
step_max=step_max,
space=hp.uniform,
optimizer=tpe,
max_evals=max_evals,
)
else:
step_best = step
dbi_eval(step=step_best)
optimal_steps.append(step_best)
norms_off_diagonal_restriction.append(dbi_eval.off_diagonal_norm)
# find best d
idx_max_loss = np.argmin(norms_off_diagonal_restriction)
flip = flip_list[idx_max_loss]
step_optimal = optimal_steps[idx_max_loss]
dbi_eval = deepcopy(dbi_object)
if idx_max_loss == len(d_list) and compare_canonical is True:
andrea-pasquale marked this conversation as resolved.
Show resolved Hide resolved
# canonical
dbi_eval(step=step_optimal, mode=DoubleBracketGeneratorType.canonical)

else:
d_optimal = flip * d_list[idx_max_loss]
dbi_eval(step=step_optimal, d=d_optimal)
return dbi_eval, idx_max_loss, step_optimal, flip
andrea-pasquale marked this conversation as resolved.
Show resolved Hide resolved


def cs_angle_sgn(dbi_object, d):
"""Calculates the sign of Cauchy-Schwarz Angle :math:`\\langle W(Z), W({\\rm canonical}) \\rangle_{\\rm HS}`."""
norm = np.trace(
np.dot(
np.conjugate(
dbi_object.commutator(dbi_object.diagonal_h_matrix, dbi_object.h.matrix)
).T,
dbi_object.commutator(d, dbi_object.h.matrix),
)
)
return np.sign(norm)
Loading
Loading