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

Integrate QRAO into Qiskit Optimization #487

Merged
merged 89 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
14b75fa
add qrao files
a-matsuo Mar 24, 2023
837326b
support primitives and remove opflow
a-matsuo Apr 13, 2023
6e914ce
update qrao
a-matsuo Apr 16, 2023
32acacb
update qrao
a-matsuo Apr 17, 2023
31507c1
add expecation_values getter
a-matsuo Apr 17, 2023
b210cb0
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo Apr 17, 2023
11a5e40
inherit OptimizationAlgorithm
a-matsuo Apr 21, 2023
ba244a2
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 8, 2023
6a67943
add unittests for encoding
a-matsuo May 8, 2023
41f86eb
add unittests for optimizer
a-matsuo May 9, 2023
b4277ad
add unittests for optimizer
a-matsuo May 9, 2023
4408846
add reno and unittests for magic rounding
a-matsuo May 10, 2023
efcb66d
clean up
a-matsuo May 10, 2023
30c8794
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 10, 2023
2ae38b0
remove a unnecessary file
a-matsuo May 11, 2023
fc4d379
update the code
a-matsuo May 11, 2023
27ca8f1
add tutorial and update the code
a-matsuo May 12, 2023
668add2
update pylintdict
a-matsuo May 12, 2023
305a46e
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 12, 2023
9c3ac42
fix lint
a-matsuo May 12, 2023
872927d
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo May 17, 2023
59ecdd6
Update qiskit_optimization/algorithms/qrao/magic_rounding.py
a-matsuo May 17, 2023
40ae277
Update releasenotes/notes/qrao-89d5ff1d2927de64.yaml
a-matsuo May 17, 2023
7fb0f40
update the code
a-matsuo May 17, 2023
96784fa
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 17, 2023
d7513bb
add explanations and reflect comments
a-matsuo May 18, 2023
558ee28
update codes
a-matsuo May 19, 2023
0c438d5
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 19, 2023
02ec72a
fix
a-matsuo May 22, 2023
da34116
update the code
a-matsuo May 23, 2023
8c710d3
fix lint
a-matsuo May 23, 2023
a9fed9c
Fix docs so they build
woodsp-ibm May 23, 2023
f6c6e05
fix lint
a-matsuo May 24, 2023
9ecfd1c
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 24, 2023
8610ca1
Merge branch 'qrao' of github.com:a-matsuo/qiskit-optimization into qrao
a-matsuo May 24, 2023
810dc45
fix spell
a-matsuo May 24, 2023
6d62a05
fix spell
a-matsuo May 24, 2023
373987e
fix spell
a-matsuo May 24, 2023
0e787fc
test
a-matsuo May 29, 2023
58973a3
test
a-matsuo May 29, 2023
cc643ae
update
a-matsuo May 29, 2023
5a87be2
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 29, 2023
133105a
fix lint
a-matsuo May 29, 2023
73de655
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 29, 2023
ba59e95
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo May 29, 2023
424ea00
use assertalmost equal in unittest
a-matsuo May 29, 2023
7f4e5bd
update
a-matsuo May 30, 2023
402b025
fix
a-matsuo May 30, 2023
863f73a
Merge branch 'main' into qrao
a-matsuo Jun 1, 2023
f76c50b
rerun tutorial
a-matsuo Jun 2, 2023
12809dd
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo Jun 2, 2023
32c01a8
Merge branch 'qrao' of github.com:a-matsuo/qiskit-optimization into qrao
a-matsuo Jun 2, 2023
02c0a7c
add unittests for max per qubit= 2 and 1
a-matsuo Jun 5, 2023
df37bd9
Merge branch 'main' into qrao
woodsp-ibm Jun 5, 2023
3523a44
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo Jun 7, 2023
a8be7b4
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo Jun 7, 2023
1e8bc6f
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo Jun 7, 2023
dfde28b
fix docs
a-matsuo Jun 7, 2023
cdc675d
lint
a-matsuo Jun 7, 2023
948152d
add unittest quadratic objective
a-matsuo Jun 7, 2023
e71f660
update optimizer unittest
a-matsuo Jun 7, 2023
7b3c9e3
replaces rustworkx with networkx
t-imamichi Jun 12, 2023
0d6e7ce
minor updates of explanation
t-imamichi Jun 12, 2023
d16fca9
Merge branch 'main' into qrao
t-imamichi Jun 12, 2023
da4142e
fix docstrings
t-imamichi Jun 13, 2023
8b13f0c
update an error message
t-imamichi Jun 14, 2023
d0dec2c
Merge branch 'main' into qrao
t-imamichi Jun 14, 2023
d458560
update error messages
t-imamichi Jun 15, 2023
6380107
fix lint
t-imamichi Jun 15, 2023
0fb1656
Merge branch 'main' into qrao
woodsp-ibm Aug 29, 2023
ff8ee8e
update tutorial and qiskit_algorithms
a-matsuo Sep 4, 2023
a90bea3
Merge branch 'main' into qrao
woodsp-ibm Sep 5, 2023
57119a4
Merge branch 'main' into qrao
woodsp-ibm Sep 5, 2023
caac634
update
a-matsuo Sep 6, 2023
27c6c73
Merge branch 'qrao' of github.com:a-matsuo/qiskit-optimization into qrao
a-matsuo Sep 6, 2023
0fa0025
fix lint
a-matsuo Sep 6, 2023
8e0cb42
fix
a-matsuo Sep 7, 2023
74dec95
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo Sep 7, 2023
a5ec643
Update docs/tutorials/13_quantum_random_access_optimizer.ipynb
a-matsuo Sep 7, 2023
c1c329d
fix
a-matsuo Sep 7, 2023
cbba4f8
Update qiskit_optimization/algorithms/qrao/__init__.py
a-matsuo Sep 7, 2023
4b2ea88
Update releasenotes/notes/qrao-89d5ff1d2927de64.yaml
a-matsuo Sep 7, 2023
9f61f4c
Update test/algorithms/qrao/test_magic_rounding.py
a-matsuo Sep 7, 2023
bf16e25
Update test/algorithms/qrao/test_quantum_random_access_optimizer.py
a-matsuo Sep 7, 2023
3b4570e
fix mypy
a-matsuo Sep 7, 2023
e494613
Merge remote-tracking branch 'upstream/main' into qrao
a-matsuo Sep 7, 2023
6e1f1c3
fix
a-matsuo Sep 7, 2023
d5ffb28
fix
a-matsuo Sep 7, 2023
208daad
change the index number
a-matsuo Sep 8, 2023
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
736 changes: 736 additions & 0 deletions docs/tutorials/13_quantum_random_access_optimizer.ipynb

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions qiskit_optimization/algorithms/qrao/magic_rounding.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ def basis_sampling(self):

@staticmethod
def _make_circuits(
circ: QuantumCircuit, bases: np.ndarray[Any, Any], vars_per_qubit: int
circuit: QuantumCircuit, bases: np.ndarray[Any, Any], vars_per_qubit: int
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
) -> List[QuantumCircuit]:
"""Make a list of circuits to measure in the given magic bases.

Args:
circ: Quantum circuit to measure.
circuit: Quantum circuit to measure.
bases: List of magic bases to measure in.
vars_per_qubit: Number of variables per qubit.

Expand All @@ -128,11 +128,11 @@ def _make_circuits(
circuits = []
for basis in bases:
if vars_per_qubit == 3:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
qc = circ.compose(_z_to_31p_qrac_basis_circuit(basis).inverse(), inplace=False)
qc = circuit.compose(_z_to_31p_qrac_basis_circuit(basis).inverse(), inplace=False)
elif vars_per_qubit == 2:
qc = circ.compose(_z_to_21p_qrac_basis_circuit(basis).inverse(), inplace=False)
qc = circuit.compose(_z_to_21p_qrac_basis_circuit(basis).inverse(), inplace=False)
elif vars_per_qubit == 1:
qc = circ.copy()
qc = circuit.copy()
qc.measure_all()
circuits.append(qc)
return circuits
Expand Down Expand Up @@ -319,6 +319,7 @@ def _sample_bases_weighted(
corresponds to the number of shots to use for the corresponding basis in
the bases array.
"""
# pylint: disable=C0401
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
# First, we make sure all Pauli expectation values have absolute value
# at most 1. Otherwise, some of the probabilities computed below might
# be negative.
Expand Down Expand Up @@ -365,11 +366,11 @@ def _sample_bases_weighted(
bases, basis_shots = np.unique(bases_, axis=0, return_counts=True)
return bases, basis_shots

def round(self, ctx: RoundingContext) -> MagicRoundingResult:
def round(self, rounding_context: RoundingContext) -> MagicRoundingResult:
"""Perform magic rounding using the given RoundingContext.

Args:
ctx: The context containing the information needed for the rounding.
rounding_context: The context containing the information needed for the rounding.

Returns:
MagicRoundingResult: The results of the magic rounding process.
Expand All @@ -378,11 +379,11 @@ def round(self, ctx: RoundingContext) -> MagicRoundingResult:
NotImplementedError: If the circuit is not available for magic rounding.
ValueError: If the sampler is not configured with a number of shots.
"""
expectation_values = ctx.expectation_values
circuit = ctx.circuit
q2vars = ctx.encoding.q2vars
var2op = ctx.encoding.var2op
vars_per_qubit = ctx.encoding.max_vars_per_qubit
expectation_values = rounding_context.expectation_values
circuit = rounding_context.circuit
q2vars = rounding_context.encoding.q2vars
var2op = rounding_context.encoding.var2op
vars_per_qubit = rounding_context.encoding.max_vars_per_qubit

if circuit is None:
raise NotImplementedError(
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -421,10 +422,10 @@ def round(self, ctx: RoundingContext) -> MagicRoundingResult:
soln_samples = [
SolutionSample(
x=np.asarray([int(bit) for bit in soln]),
fval=ctx.encoding.problem.objective.evaluate([int(bit) for bit in soln]),
fval=rounding_context.encoding.problem.objective.evaluate([int(bit) for bit in soln]),
probability=count / self._shots,
status=OptimizationResultStatus.SUCCESS
if ctx.encoding.problem.is_feasible([int(bit) for bit in soln])
if rounding_context.encoding.problem.is_feasible([int(bit) for bit in soln])
else OptimizationResultStatus.INFEASIBLE,
)
for soln, count in soln_counts.items()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ def _qrac_state_prep_1q(bit_list: List[int]) -> QuantumCircuit:

if len(bit_list) == 3:
# Prepare (3,1,p)-qrac
# In the following lines, the input bits are XOR'd to match the
# In the following lines, the input bits are XORed to match the
# conventions used in the paper.
# To understand why this transformation happens,
# observe that the two states that define each magic basis
# correspond to the same bitstrings but with a global bitflip.
# correspond to the same bitstrings but with a global bit flip.
# Thus the three bits of information we use to construct these states are:
# base_index0,base_index1 : two bits to pick one of four magic bases
# bit_flip: one bit to indicate which magic basis projector we are interested in.
Expand Down Expand Up @@ -152,15 +152,15 @@ def _qrac_state_prep_1q(bit_list: List[int]) -> QuantumCircuit:
return circ


def _qrac_state_prep_multiqubit(
dvars: List[int],
def _qrac_state_prep_multi_qubit(
x: List[int],
q2vars: List[List[int]],
max_vars_per_qubit: int,
) -> QuantumCircuit:
"""Prepares a multiqubit QRAC state.
"""Prepares a multi qubit QRAC state.

Args:
dvars: The state of each decision variable (0 or 1).
x: The state of each decision variable (0 or 1).
q2vars: A list of lists of integers. Each inner list contains the indices of decision variables
mapped to a specific qubit.
max_vars_per_qubit: The maximum number of decision variables that can be mapped to a
Expand All @@ -170,12 +170,12 @@ def _qrac_state_prep_multiqubit(
A QuantumCircuit object representing the prepared state.

Raises:
ValueError: If any qubit is associated with more than ``max_vars_per_qubit`` variables.
ValueError: If a decision variable in ``q2vars`` is not included in ``dvars``.
ValueError: If there are unused decision variables in `dvars` after mapping to qubits.
ValueError: If any qubit is associated with more than `max_vars_per_qubit` variables.
ValueError: If a decision variable in ``q2vars`` is not included in `x`.
ValueError: If there are unused decision variables in `x` after mapping to qubits.
"""
# Create a set of all remaining decision variables
remaining_dvars = set(range(len(dvars)))
remaining_dvars = set(range(len(x)))
# Create a list to store the binary mappings of each qubit to its corresponding decision variables
variable_mappings: List[List[int]] = []
# Check that each qubit is associated with at most max_vars_per_qubit variables
Expand All @@ -193,7 +193,7 @@ def _qrac_state_prep_multiqubit(
# to the qubit bits
for dvar in qi_vars:
try:
qi_bits.append(dvars[dvar])
qi_bits.append(x[dvar])
except IndexError:
raise ValueError(f"Decision variable not included in dvars: {dvar}") from None
try:
Expand All @@ -213,7 +213,7 @@ def _qrac_state_prep_multiqubit(
if remaining_dvars:
raise ValueError(f"Not all dvars were included in q2vars: {remaining_dvars}")

# Prepare the individual qrac circuit and combine them into a multiqubit circuit
# Prepare the individual qrac circuit and combine them into a multi qubit circuit
qracs = [_qrac_state_prep_1q(qi_bits) for qi_bits in variable_mappings]
qrac_circ = reduce(lambda x, y: x.tensor(y), qracs)
return qrac_circ
Expand Down Expand Up @@ -272,7 +272,7 @@ def var2op(self) -> Dict[int, Tuple[int, SparsePauliOp]]:

@property
def q2vars(self) -> List[List[int]]:
"""Each element contains the list of decision variable indice(s) encoded on that qubit"""
"""Each element contains the list of decision variable indices encoded on that qubit"""
return self._q2vars

@property
Expand Down Expand Up @@ -556,14 +556,14 @@ def encode(self, problem: QuadraticProgram) -> None:

self.freeze()

def state_preparation_circuit(self, dvars: List[int]) -> QuantumCircuit:
def state_preparation_circuit(self, x: List[int]) -> QuantumCircuit:
"""
Generate a circuit that prepares the state corresponding to the given binary string.

Args:
dvars: A list of binary values to be encoded into the state.
x: A list of binary values to be encoded into the state.

Returns:
A QuantumCircuit that prepares the state corresponding to the given binary string.
"""
return _qrac_state_prep_multiqubit(dvars, self.q2vars, self.max_vars_per_qubit)
return _qrac_state_prep_multi_qubit(x, self.q2vars, self.max_vars_per_qubit)
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def solve_relaxed(
)
relaxed_result.time_taken = time.time() - start_time_relaxed

# Get auxiliary expectaion values for rounding.
# Get auxiliary expectation values for rounding.
if relaxed_result.aux_operators_evaluated is not None:
expectation_values = [v[0] for v in relaxed_result.aux_operators_evaluated]
else:
Expand Down
2 changes: 1 addition & 1 deletion qiskit_optimization/algorithms/qrao/rounding_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class RoundingScheme(ABC):
"""Base class for a rounding scheme"""

@abstractmethod
def round(self, ctx: RoundingContext) -> RoundingResult:
def round(self, rounding_context: RoundingContext) -> RoundingResult:
"""Perform rounding

Returns: an instance of RoundingResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ def __init__(self, *, seed: Optional[int] = None):
super().__init__()
self.rng = np.random.RandomState(seed)
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved

def round(self, ctx: RoundingContext) -> SemideterministicRoundingResult:
def round(self, rounding_context: RoundingContext) -> SemideterministicRoundingResult:
"""Perform semideterministic rounding

Args:
ctx: Rounding context containing information about the problem and solution.
rounding_context: Rounding context containing information about the problem and solution.

Returns:
Result containing the rounded solution.
Expand All @@ -63,30 +63,30 @@ def round(self, ctx: RoundingContext) -> SemideterministicRoundingResult:
def sign(val) -> int:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
return 0 if (val > 0) else 1

if ctx.expectation_values is None:
if rounding_context.expectation_values is None:
raise NotImplementedError(
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"Semideterministric rounding requires the expectation values of the ",
"``RoundingContext`` to be available, but they are not.",
)
rounded_vars = np.array(
[
sign(e) if not np.isclose(0, e) else self.rng.randint(2)
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
for e in ctx.expectation_values
for e in rounding_context.expectation_values
]
)

soln_samples = [
SolutionSample(
x=np.asarray(rounded_vars),
fval=ctx.encoding.problem.objective.evaluate(rounded_vars),
fval=rounding_context.encoding.problem.objective.evaluate(rounded_vars),
probability=1.0,
status=OptimizationResultStatus.SUCCESS
if ctx.encoding.problem.is_feasible(rounded_vars)
if rounding_context.encoding.problem.is_feasible(rounded_vars)
else OptimizationResultStatus.INFEASIBLE,
)
]

result = SemideterministicRoundingResult(
expectation_values=ctx.expectation_values, samples=soln_samples
expectation_values=rounding_context.expectation_values, samples=soln_samples
)
return result
6 changes: 3 additions & 3 deletions test/algorithms/qrao/test_quantum_random_access_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_qrac_state_prep(self):
with self.subTest(msg="(3,1,p) QRAC"):
encoding = QuantumRandomAccessEncoding(3)
encoding.encode(self.problem)
state_prep_circ = encoding.state_preparation_circuit(dvars=dvars)
state_prep_circ = encoding.state_preparation_circuit(x=dvars)
circ = QuantumCircuit(1)
beta = np.arccos(1 / np.sqrt(3))
circ.r(np.pi - beta, np.pi / 4, 0)
Expand All @@ -149,7 +149,7 @@ def test_qrac_state_prep(self):
with self.subTest(msg="(2,1,p) QRAC"):
encoding = QuantumRandomAccessEncoding(2)
encoding.encode(self.problem)
state_prep_circ = encoding.state_preparation_circuit(dvars=dvars)
state_prep_circ = encoding.state_preparation_circuit(x=dvars)
circ = QuantumCircuit(2)
circ.x(0)
circ.r(-3 * np.pi / 4, -np.pi / 2, 0)
Expand All @@ -159,7 +159,7 @@ def test_qrac_state_prep(self):
with self.subTest(msg="(1,1,p) QRAC"):
encoding = QuantumRandomAccessEncoding(1)
encoding.encode(self.problem)
state_prep_circ = encoding.state_preparation_circuit(dvars=dvars)
state_prep_circ = encoding.state_preparation_circuit(x=dvars)
circ = QuantumCircuit(3)
circ.x(0)
circ.x(1)
Expand Down