Skip to content

Commit

Permalink
Add qubo solver
Browse files Browse the repository at this point in the history
  • Loading branch information
Elscrux committed Sep 28, 2023
1 parent 69233c9 commit 1074594
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 2 deletions.
42 changes: 42 additions & 0 deletions qiskit/qubo/qubo_qiskit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import copy
import sys

from qiskit.algorithms.minimum_eigensolvers import QAOA
from qiskit.algorithms.optimizers import COBYLA
from qiskit.primitives import Sampler
from qiskit_optimization import QuadraticProgram
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit_optimization.problems import VarType

if len(sys.argv) != 3:
raise TypeError('This script expects exactly 2 arguments. Input file (argument 1) and output file (argument 2).')

input_path = sys.argv[1]
output_path = sys.argv[2]

qp = QuadraticProgram()
qp.read_from_lp_file(input_path)


def relax_problem(problem):
"""Change all variables to continuous."""
relaxed_problem = copy.deepcopy(problem)
for variable in relaxed_problem.variables:
variable.vartype = VarType.CONTINUOUS

return relaxed_problem

qubo = qp
# qubo = relax_problem(QuadraticProgramToQubo().convert(qp))
# print(qp.prettyprint())

qaoa_mes = QAOA(Sampler(), optimizer=COBYLA(), initial_point=[0.0, 1.0])

qaoa = MinimumEigenOptimizer(qaoa_mes)

qaoa_result = qaoa.solve(qubo)
print(qaoa_result.prettyprint())

f = open(output_path, 'w')
f.write(qaoa_result.prettyprint())
f.close()
2 changes: 1 addition & 1 deletion qiskit/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
numpy
pygmlparser
qiskit == 0.44.*
qiskit_optimization
qiskit_optimization[cplex]
qiskit-aer
10 changes: 9 additions & 1 deletion src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.kit.provideq.toolbox.SolveRequest;
import edu.kit.provideq.toolbox.featuremodel.SolveFeatureModelRequest;
import edu.kit.provideq.toolbox.maxcut.SolveMaxCutRequest;
import edu.kit.provideq.toolbox.qubo.SolveQuboRequest;
import edu.kit.provideq.toolbox.sat.SolveSatRequest;

/**
Expand Down Expand Up @@ -38,7 +39,14 @@ public enum ProblemType {
* @see <a href="https://sdq.kastel.kit.edu/publications/pdfs/kowal2016b.pdf">
* "Explaining Anomalies in Feature Models", Kowal et al., 2026</a>
*/
FEATURE_MODEL_ANOMALY_VOID("feature-model-anomaly-void", SolveFeatureModelRequest.class);
FEATURE_MODEL_ANOMALY_VOID("feature-model-anomaly-void", SolveFeatureModelRequest.class),
/**
* QUBO (Quadratic Unconstrained Binary Optimization)
* A combinatorial optimization problem.
* For a given quadratic term with binary decision variables,
* find the minimal variable assignment of the term.
*/
QUBO("qubo", SolveQuboRequest.class);

private final String id;
private final Class<? extends SolveRequest<?>> requestType;
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/edu/kit/provideq/toolbox/qubo/QuboMetaSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package edu.kit.provideq.toolbox.qubo;

import edu.kit.provideq.toolbox.meta.MetaSolver;
import edu.kit.provideq.toolbox.meta.Problem;
import edu.kit.provideq.toolbox.meta.ProblemType;
import edu.kit.provideq.toolbox.meta.setting.MetaSolverSetting;
import edu.kit.provideq.toolbox.qubo.solvers.QiskitQuboSolver;
import edu.kit.provideq.toolbox.qubo.solvers.QuboSolver;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* Simple {@link MetaSolver} for MaxCut problems.
*/
@Component
public class QuboMetaSolver extends MetaSolver<String, String, QuboSolver> {

@Autowired
public QuboMetaSolver(QiskitQuboSolver qiskitQuboSolver) {
super(ProblemType.QUBO, qiskitQuboSolver);
}

@Override
public QuboSolver findSolver(
Problem<String> problem,
List<MetaSolverSetting> metaSolverSettings) {
return (new ArrayList<>(this.solvers)).get((new Random()).nextInt(this.solvers.size()));
}

@Override
public List<String> getExampleProblems() {
return List.of("""
Maximize
3x + y
Subject To
Binary
x y
End
""");
}
}
11 changes: 11 additions & 0 deletions src/main/java/edu/kit/provideq/toolbox/qubo/SolveQuboRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package edu.kit.provideq.toolbox.qubo;

import edu.kit.provideq.toolbox.SolveRequest;

/**
* POST Requests to /solve/qubo should have a response body of this form.
* The needed formula the qubo formula to solve in the
* <a href="https://www.gurobi.com/documentation/current/refman/lp_format.html">LP format</a>.
*/
public class SolveQuboRequest extends SolveRequest<String> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package edu.kit.provideq.toolbox.qubo.solvers;

import edu.kit.provideq.toolbox.PythonProcessRunner;
import edu.kit.provideq.toolbox.Solution;
import edu.kit.provideq.toolbox.SubRoutinePool;
import edu.kit.provideq.toolbox.meta.Problem;
import edu.kit.provideq.toolbox.meta.ProblemType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class QiskitQuboSolver extends QuboSolver {
private final String quboPath;
private final ApplicationContext context;

@Autowired
public QiskitQuboSolver(
@Value("${qiskit.directory.qubo}") String quboPath,
ApplicationContext context) {
this.quboPath = quboPath;
this.context = context;
}

@Override
public String getName() {
return "Qiskit Qubo";
}

@Override
public boolean canSolve(Problem<String> problem) {
return problem.type() == ProblemType.QUBO;
}

@Override
public void solve(Problem<String> problem, Solution<String> solution,
SubRoutinePool subRoutinePool) {
// Run Qiskit solver via console
var processResult = context
.getBean(
PythonProcessRunner.class,
quboPath,
"qubo_qiskit.py")
.addProblemFilePathToProcessCommand()
.addSolutionFilePathToProcessCommand()
.problemFileName("problem.lp")
.run(problem.type(), solution.getId(), problem.problemData());

// Return if process failed
if (!processResult.success()) {
solution.setDebugData(processResult.output());
solution.abort();
return;
}

solution.setSolutionData(processResult.output());
solution.complete();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package edu.kit.provideq.toolbox.qubo.solvers;

import edu.kit.provideq.toolbox.meta.ProblemSolver;

public abstract class QuboSolver implements ProblemSolver<String, String> {
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gams.directory.sat=${gams.directory}/sat

qiskit.directory=qiskit
qiskit.directory.max-cut=${qiskit.directory}/max-cut
qiskit.directory.qubo=${qiskit.directory}/qubo

cirq.directory=cirq
cirq.directory.max-cut=${cirq.directory}/max-cut
Expand Down

0 comments on commit 1074594

Please sign in to comment.