Skip to content

Commit 739c4f1

Browse files
authored
Merge pull request #100 from eclipse-qrisp/QAOAQIRO_experiments
Qaoaqiro experiments
2 parents 0491a76 + b1fdd31 commit 739c4f1

29 files changed

+507
-429
lines changed

documentation/source/general/tutorial/QIROtutorial.rst

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ To run the instance and solve the optimization problem we use the :meth:`.run <q
111111
Maximum independent set example
112112
===============================
113113

114-
We now investigate a code example for the maximum independent set problem.
114+
We now investigate a code example for the maximum independent set problem. The in-depth explanation will focus on the unconnected cost operator implementation displayed.
115+
In constrast, our :ref:` general QAOA implementation for the MIS problem <maxIndepSetQAOA>` is based on a constrained mixer approach. This can also be used for the QIRO implementation,
116+
which we show at the end of this tutorial!
115117

116118
Preliminaries
117119
-------------
@@ -166,10 +168,10 @@ All in all, the function remains straight forward. We employ a ``find_max`` subr
166168
return new_graph, solutions, sign, exclusions
167169

168170
As you might have noticed in the code above, we add the nodes that are included into (respective excluded from) the solution to a list ``solutions`` (``exclusions``).
169-
This allows us to directly :ref:`recycle the QAOA code <maxIndepSetQAOA>` for the ``cost_operator``, ``mixer`` and ``init_function`` of the original QAOA implementation with minor adjustments.
171+
This allows us to directly use the same ideas for the ``cost_operator``, ``mixer`` and ``init_function`` of the original unconstrained QAOA theory with minor adjustments.
170172

171-
Since we have to consider nodes that are already asigned to be in the solution set, or exluded from the algorithm, we do not want to apply these functions to said nodes.
172-
We therefore include some simple lines of code into the functions, for example in the ``qiro_RXMixer``:
173+
Since we have to consider nodes that are already asigned to be in the solution set, or exluded from the algorithm, we do not want to apply ``cost_operator`` or ``mixer`` to said nodes.
174+
We therefore include some simple lines of code into the functions to take this into account, for example the ``if not``-statement in the ``qiro_RXMixer``:
173175

174176
::
175177

@@ -182,6 +184,28 @@ We therefore include some simple lines of code into the functions, for example i
182184
rx(2 * beta, qv[i])
183185
return RX_mixer
184186

187+
188+
Similarly an ``if not``-statement is included in the cost operator, which is named ``create_max_indep_cost_operator_reduced`` due to it respecting the problem reduction:
189+
190+
::
191+
192+
def create_max_indep_cost_operator_reduced(problem_updated):
193+
194+
problem = problem_updated[0]
195+
solutions = problem_updated[1]
196+
def cost_operator(qv, gamma):
197+
for pair in list(problem.edges()):
198+
#cx(qv[pair[0]], qv[pair[1]])
199+
rzz(3*gamma, qv[pair[0]], qv[pair[1]])
200+
rz(-gamma, qv[pair[0]])
201+
rz(-gamma, qv[pair[1]])
202+
for i in problem.nodes():
203+
# DONT apply gates on nodes in the solution set
204+
if not i in solutions:
205+
rz(gamma, qv[i])
206+
207+
return cost_operator
208+
185209
With the preliminaries out of the way, let us jump right into the code example:
186210

187211

@@ -249,7 +273,6 @@ We can further compare our results to the `NetworkX MIS algorithm <https://netwo
249273
print("Networkx solution")
250274
print(nx.approximation.maximum_independent_set(G))
251275

252-
Chances are, you will see a result in the QIRO implementation, that is better than the classical algorithm provided by Networkx!
253276

254277
As a final caveat, we can look at the graph we are left with after all reduction steps.
255278

@@ -261,6 +284,29 @@ As a final caveat, we can look at the graph we are left with after all reduction
261284
plt.title('Final QIRO graph')
262285
plt.show()
263286

287+
288+
Constrained mixer implementation
289+
--------------------------------
290+
291+
Before we end this tutorial we want to show you what the constrained mixer implementation looks like for the MIS QIRO algorithm. In analogy to our :ref:` general QAOA implementation for the MIS problem <maxIndepSetQAOA>`
292+
we use the :ref:`qiro_rz_mixer <QIRO>` as the mixer and the :ref:`create_max_indep_controlled_mixer_reduced <maxIndependentSetQIRO>` as the cost operator. In principle, these functions do the exact same thing as the general implementations,
293+
but they respect the solutions and exclusions chosen via the update routine. We suggest to try this instance with larger graph sizes (more than 20 nodes).
294+
295+
::
296+
297+
# assign the correct update functions for constrained qiro
298+
qiro_instance = QIROProblem(G,
299+
create_max_indep_replacement_routine,
300+
qiro_rz_mixer,
301+
create_max_indep_controlled_mixer_reduced,
302+
create_max_indep_set_cl_cost_function,
303+
qiro_max_indep_set_init_function,
304+
)
305+
306+
# We run the qiro instance and get the results!
307+
res_qiro = qiro_instance.run_qiro(qarg=qarg, depth = 3, n_recursions = 1)
308+
309+
264310
Congratulations, you have reached the end of the tutorial and are now capable of solving the MIS problem in Qrisp!
265311
Should your appetite not be satisfied, we advise you to check out our other QIRO implementations:
266312

documentation/source/reference/Algorithms/qiro/QIRO.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ Collection of mixers and auxiliary functions
3636

3737
.. autosummary::
3838

39-
qiro_RXMixer
39+
qiro_rx_mixer
40+
qiro_rz_mixer
41+
qiro_controlled_RX_mixer_gen
4042
qiro_init_function
4143
find_max
4244

documentation/source/reference/Algorithms/qiro/implementations/QIROMaxClique.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Example implementation
4242
::
4343

4444
from qrisp import QuantumVariable
45-
from qrisp.qiro import QIROProblem, create_max_clique_replacement_routine, create_max_clique_cost_operator_reduced, qiro_RXMixer, qiro_init_function
45+
from qrisp.qiro import QIROProblem, create_max_clique_replacement_routine, create_max_clique_cost_operator_reduced, qiro_rx_mixer, qiro_init_function
4646
from qrisp.qaoa import max_clique_problem, create_max_clique_cl_cost_function
4747
import matplotlib.pyplot as plt
4848
import networkx as nx
@@ -56,7 +56,7 @@ Example implementation
5656
qiro_instance = QIROProblem(problem=G,
5757
replacement_routine= reate_max_clique_replacement_routine,
5858
cost_operator=create_max_clique_cost_operator_reduced,
59-
mixer=qiro_RXMixer,
59+
mixer=qiro_rx_mixer,
6060
cl_cost_function=create_max_clique_cl_cost_function,
6161
init_function=qiro_init_function
6262
)

documentation/source/reference/Algorithms/qiro/implementations/QIROMaxIndep.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,23 @@ QIRO Cost operator
3434

3535
.. autofunction:: create_max_indep_cost_operator_reduced
3636

37+
QIRO with Constrained mixer
38+
---------------------------
39+
40+
.. autofunction:: create_max_indep_controlled_mixer_reduced
41+
42+
.. autofunction:: qiro_max_indep_set_init_function
43+
3744

3845
Example implementation
3946
----------------------
47+
48+
The implementation below is for the standard unconstrained cost operator implementation. An implementation with a controlled mixer ansatz is shown in the tutorial section.
49+
4050
::
4151

4252
from qrisp import QuantumVariable
43-
from qrisp.qiro import QIROProblem, create_max_indep_replacement_routine, create_max_indep_cost_operator_reduced, qiro_RXMixer, qiro_init_function
53+
from qrisp.qiro import QIROProblem, create_max_indep_replacement_routine, create_max_indep_cost_operator_reduced, qiro_rx_mixer, qiro_init_function
4454
from qrisp.qaoa import create_max_indep_set_cl_cost_function
4555
import matplotlib.pyplot as plt
4656
import networkx as nx
@@ -53,7 +63,7 @@ Example implementation
5363
qiro_instance = QIROProblem(G,
5464
replacement_routine=create_max_indep_replacement_routine,
5565
cost_operator=create_max_indep_cost_operator_reduced,
56-
mixer=qiro_RXMixer,
66+
mixer=qiro_rx_mixer,
5767
cl_cost_function=create_max_indep_set_cl_cost_function,
5868
init_function=qiro_init_function
5969
)

documentation/source/reference/Algorithms/qiro/implementations/QIROMaxSat.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Example implementation
6767

6868
from qrisp import QuantumVariable
6969
from qrisp.qaoa import create_maxsat_cl_cost_function
70-
from qrisp.qiro import QIROProblem, qiro_init_function, qiro_RXMixer, create_maxsat_replacement_routine, create_maxsat_cost_operator_reduced
70+
from qrisp.qiro import QIROProblem, qiro_init_function, qiro_rx_mixer, create_maxsat_replacement_routine, create_maxsat_cost_operator_reduced
7171

7272
clauses = [[1,2,-3],[1,4,-6],[4,5,6],[1,3,-4],[2,4,5],[1,3,5],[-2,-3,6],[1,7,8],[3,-7,-8],[3,4,8],[4,5,8],[1,2,7]]
7373
num_vars = 8
@@ -77,7 +77,7 @@ Example implementation
7777
qiro_instance = QIROProblem(problem = problem,
7878
replacement_routine = create_maxsat_replacement_routine,
7979
cost_operator = create_maxsat_cost_operator_reduced,
80-
mixer = qiro_RXMixer,
80+
mixer = qiro_rx_mixer,
8181
cl_cost_function = create_maxsat_cl_cost_function,
8282
init_function = qiro_init_function
8383
)

documentation/source/reference/Algorithms/qiro/implementations/QIROMaxSetPack.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Example implementation
2727
::
2828

2929
from qrisp import QuantumVariable
30-
from qrisp.qiro import QIROProblem, create_max_indep_replacement_routine, create_max_indep_cost_operator_reduced, qiro_RXMixer, qiro_init_function
30+
from qrisp.qiro import QIROProblem, create_max_indep_replacement_routine, create_max_indep_cost_operator_reduced, qiro_rx_mixer, qiro_init_function
3131
from qrisp.qaoa import create_max_indep_set_cl_cost_function
3232
import matplotlib.pyplot as plt
3333
import networkx as nx
@@ -41,7 +41,7 @@ Example implementation
4141
qiro_instance = QIROProblem(G,
4242
replacement_routine=create_max_indep_replacement_routine,
4343
cost_operator=create_max_indep_cost_operator_reduced,
44-
mixer=qiro_RXMixer,
44+
mixer=qiro_rx_mixer,
4545
cl_cost_function=create_max_indep_set_cl_cost_function,
4646
init_function=qiro_init_function
4747
)

src/qrisp/algorithms/qaoa/mixers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def portfolio_mixer():
343343
mixer_op(qv, np.pi/8)
344344
345345
"""
346-
from qrisp.misc.dicke_state import dicke_state
346+
from qrisp.alg_primitives import dicke_state
347347

348348
def inv_prepare_dicke(qv, k):
349349
with invert():

src/qrisp/algorithms/qaoa/problems/maxSat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def create_maxsat_cost_polynomials(problem):
4444
cost_polynomials = []
4545
for clause in clauses:
4646
C = 1 - sp.prod((1-symbols[index-1]) if index>0 else symbols[-index-1] for index in clause)
47+
4748
cost_polynomials.append(C)
4849

4950
return cost_polynomials, symbols

src/qrisp/algorithms/qaoa/qaoa_problem.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,6 @@ def run(self, qarg, depth, mes_kwargs = {}, max_iter = 50, init_type = "random",
522522
self.cost_operator(qarg, optimal_theta[i])
523523
self.mixer(qarg, optimal_theta[i+depth])
524524
opt_res = qarg.get_measurement(**mes_kwargs)
525-
526525
return opt_res
527526

528527
def train_function(self, qarg, depth, mes_kwargs = {}, max_iter = 50, init_type = "random", optimizer="COBYLA"):

src/qrisp/algorithms/qiro/qiro_mixers.py

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
"""
1818

1919

20-
from qrisp import x, rx
20+
from qrisp import x, rx, rz, auto_uncompute, control
2121

22-
def qiro_RXMixer(solutions = [],exclusions = []):
22+
def qiro_rx_mixer(problem_updated):
2323
"""
2424
RX-Mixer for QIRO algorithm. Works analogously to the normal RX-Mixer, but respects solutions and exclusions that have been found in the QIRO reduction steps.
2525
@@ -36,14 +36,106 @@ def qiro_RXMixer(solutions = [],exclusions = []):
3636
The RX-mixer, according to the update steps that have been undertaken
3737
3838
"""
39+
40+
solutions = problem_updated[1]
41+
exclusions = problem_updated[2]
3942
union = solutions + exclusions
43+
4044
def RX_mixer(qv, beta):
4145

4246
for i in range(len(qv)):
4347
if not i in union:
4448
rx(2 * beta, qv[i])
4549
return RX_mixer
4650

51+
def qiro_rz_mixer(problem_updated):
52+
"""
53+
This function applies an RZ gate with a negative phase shift to a given quantum variable.
54+
55+
Parameters
56+
----------
57+
qv : QuantumVariable
58+
The quantum variable to which the RZ gate is applied.
59+
beta : float or sympy.Symbol
60+
The phase shift value for the RZ gate.
61+
62+
"""
63+
64+
solutions = problem_updated[1]
65+
exclusions = problem_updated[2]
66+
union = solutions + exclusions
67+
68+
def RZ_mixer(qv, beta):
69+
70+
for i in range(len(qv)):
71+
if not i in union:
72+
rz(2 * beta, qv[i])
73+
return RZ_mixer
74+
75+
76+
def qiro_controlled_RX_mixer_gen(predicate, union):
77+
r"""
78+
For a QIRO MIS instances, generate a controlled RX mixer for a given predicate function.
79+
80+
Parameters
81+
----------
82+
predicate : function
83+
A function receiving a ``QuantumVariable`` and an index $i$.
84+
This function returns a ``QuantumBool`` indicating if the predicate is satisfied for ``qv[i]``,
85+
that is, if the element ``qv[i]`` should be swapped in.
86+
union : List
87+
List of Qubits which were found to be positively or negatively correlated, i.e. they should not be mixed again.
88+
89+
90+
Returns
91+
-------
92+
controlled_RX_mixer : function
93+
A function receiving a ``QuantumVariable`` and a real parameter $\beta$.
94+
This function performs the application of the mixing operator.
95+
96+
Examples
97+
--------
98+
99+
We define the predicate function for the :ref:`MaxIndepSet <maxIndepSetQAOA>` problem. It returns ``True`` for the index (node) $i$ if
100+
all neighbors $j$ of the node $i$ in the graph $G$ are not selected, and ``False`` otherwise.
101+
102+
::
103+
104+
from qrisp import QuantumVariable, QuantumBool, h, mcx, auto_uncompute, multi_measurement
105+
import networkx as nx
106+
107+
G = nx.Graph()
108+
G.add_edges_from([(0, 1), (1, 2), (2, 0)])
109+
neighbors_dict = {node: list(G.adj[node]) for node in G.nodes()}
110+
111+
def predicate(qv,i):
112+
qbl = QuantumBool()
113+
if len(neighbors_dict[i])==0:
114+
x(qbl)
115+
else:
116+
mcx([qv[j] for j in neighbors_dict[i]],qbl,ctrl_state='0'*len(neighbors_dict[i]))
117+
return qbl
118+
119+
qv = QuantumVariable(3)
120+
h(qv)
121+
qbl = predicate(qv,0)
122+
multi_measurement([qv,qbl])
123+
# Yields: {('000', True): 0.125,('100', True): 0.125,('010', False): 0.125,('110', False): 0.125,('001', False): 0.125,('101', False): 0.125,('011', False): 0.125,('111', False): 0.125}
124+
125+
The resulting ``controlled_RX_mixer`` then only swaps the node $i$ in if all neighbors $j$ in the graph $G$ are not selected.
126+
127+
"""
128+
129+
@auto_uncompute
130+
def controlled_RX_mixer(qv, beta):
131+
m = qv.size
132+
for i in range(m):
133+
if i not in union:
134+
with control(predicate(qv,i)):
135+
rx(beta,qv[i])
136+
137+
return controlled_RX_mixer
138+
47139

48140
def qiro_init_function(solutions = [], exclusions = []):
49141
"""

0 commit comments

Comments
 (0)