Solve the Optimization Problem¶
A previous section formulated the optimization problem. This section presents the core Classiq capabilities, generates a designated quantum solution, and executes the generated algorithm on a quantum backend.
This example uses the method for a common problem: the Max Independent Set (MIS) with
networkx.star_graph(4)
, solved by a QAOAMixer algorithm with a single QAOA layer.
See the problem library.
import networkx as nx
import pyomo.core as pyo
def mis(graph: nx.Graph) -> pyo.ConcreteModel:
model = pyo.ConcreteModel()
model.x = pyo.Var(graph.nodes, domain=pyo.Binary)
@model.Constraint(graph.edges)
def independent_rule(model, node1, node2):
return model.x[node1] + model.x[node2] <= 1
model.cost = pyo.Objective(expr=sum(model.x.values()), sense=pyo.maximize)
return model
The method builds a PYOMO model, indicates the QAOA and optimizer preferences, and then uses one of these commands:
generate
– generates the quantum circuit.solve
– solves the optimization problem.get_operator
– returns the Ising Hamiltonian representing the problem objective.get_objective
– returns the PYOMO object representing the problem objective.get_initial_point
– returns the initial parameters for a parametric ansatz.classical_solution.solve
– solves the optimization problem classically.
{
"name": "mis",
"graph": [
[0.0, 1.0, 1.0, 1.0, 1.0],
[1.0, 0.0, 0.0, 0.0, 0.0],
[1.0, 0.0, 0.0, 0.0, 0.0],
[1.0, 0.0, 0.0, 0.0, 0.0],
[1.0, 0.0, 0.0, 0.0, 0.0]
],
"qaoa_preferences" : {
"qsolver": "QAOAMixer",
"qaoa_reps": 1,
}
}
The file should include the name of the problem and the required arguments for the model building function. For an MIS problem, the only argument is the underline graph in the form of an adjacency matrix. Make sure the given name is the same as the file name of the model definition.
Two extension commands are available. Open the Command Palette (Ctrl+Shift+P / Command+Shift+P) and choose one:
generate circuit
for the "Generate circuit for combinatorial optimization" commandsolve problem
for the "Solve combinatorial optimization" command
First, create the desired optimization problem as a PYOMO model. The following code snippet is a concise example of the application of the optimization engine.
import networkx as nx
graph = nx.star_graph(4)
mis_model = mis(graph)
To send the model to the Classiq backend, use the CombinatorialOptimization
package with its synthesize
and solve
commands.
from classiq.applications.combinatorial_optimization import (
CombinatorialOptimization,
QSolver,
QAOAPreferences,
)
qaoa_preferences = QAOAPreferences(qsolver=QSolver.QAOAMixer, qaoa_reps=3)
mis_problem = CombinatorialOptimization(
model=mis_model, qsolver_preferences=qaoa_preferences
)
Results¶
"Model" Command¶
The model
property exposes the functional-level model of the resulting ansatz.
Afterwards, you can synthesize the explicit circuit from it.
model = mis_problem.get_model()
or
model = mis_problem.model
"Synthesize" Command¶
The quantum circuit is returned as a GeneratedCircuit class, containing both textual and visual representations. The textual data is available in multiple formats. The visual data consists of a static image (see the figure below) and an interactive image.
qc = mis_problem.synthesize()
or
qc = mis_problem.ansatz
"Solve" Command¶
result = mis_problem.solve()
The results are organized in the VQESolverResult class and you can view it in several formats.
Serialized Output¶
print(result)
=== OPTIMAL SOLUTION ===
solution cost
--------------- ------
(0, 1, 1, 1, 1) 4
=== SOLUTION DISTRIBUTION ===
solution cost probability
--------------- ------ -------------
(0, 1, 1, 1, 1) 4 0.71
(0, 1, 1, 1, 0) 3 0.02
(0, 1, 1, 0, 1) 3 0.04
(0, 1, 0, 1, 1) 3 0.03
........ .. ....
=== OPTIMAL_PARAMETERS ===
[3.064572795460487, 0.5370940203297239, 2.869550922366777, 0.526740029882901, 3.0904332803941017, 1.417496935210913]
=== TIME ===
00:00:02.258639
Histogram¶
print(result.histogram())
Convergence Graph¶
print(result.convergence_graph)
Optimal Parameters¶
result.optimal_parameters_graph()
"Operator" Command¶
operator = mis_problem.get_operator()
print(operator.show())
-2.500 * IIIII
+0.500 * IIIIZ
+0.500 * IIIZI
+0.500 * IIZII
+0.500 * IZIII
+0.500 * ZIIII
"Objective" Command¶
print(mis_problem.get_objective())
x[0] + x[1] + x[2] + x[3] + x[4] + x[5]
"Initial Parameters" Command¶
initial_parameters = mis_problem.get_initial_point()
[0.22.., 3.09..., 0.95..., 2.83...]
"Solve Classically" Command¶
result = mis_problem.solve_classically()
best_cost=4.0 time=None solution=(0, 1, 1, 1, 1)