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

Problem graph updates #78

Merged
merged 75 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
1c2436a
Change GET /solve/ to GET /solution/
Elscrux Oct 26, 2023
724bfdd
feat: add vrp problem mask and first dummy solver
LucasBerger Mar 13, 2024
92a189b
feat: add first clustering
LucasBerger Mar 14, 2024
efa9a8f
refactor: change to adding a subroutine inside the clusterers
LucasBerger Mar 14, 2024
5379520
feat: add lkh solver
LucasBerger Mar 14, 2024
50ae385
feat: more easily make custom commands
LucasBerger Mar 16, 2024
8c9af96
feat: be able to restrieve results from a subprocess more advanced
LucasBerger Mar 18, 2024
63c1b94
fix: lkh vrp solver
LucasBerger Mar 18, 2024
bcd02be
feat: kmeans clustering and stubs for all the rest of clustering and …
LucasBerger Mar 18, 2024
c639b40
feat: two phase clustering
LucasBerger Mar 18, 2024
b805868
refactor: remove debug
LucasBerger Mar 18, 2024
69088d5
feat: add vrp to tsp to qubo solver and dwave qubo solver
LucasBerger Mar 19, 2024
f2ed721
refactor: remove debug
LucasBerger Mar 19, 2024
4f5c73f
feat: integer setting type, solver specific settings, kmeans with set…
LucasBerger Mar 19, 2024
a3d1386
doc: mark classical algorithms
LucasBerger Mar 19, 2024
621d52b
feat: environment variables in processrunner
LucasBerger Mar 19, 2024
6646b1f
feat: add first test to vrp solver
LucasBerger Mar 19, 2024
a70a2b0
feat: add more complex tests
LucasBerger Mar 19, 2024
ba2a1d3
refactor: remove duplicate code when cluster merging
LucasBerger Mar 21, 2024
661860d
refactor: further remove duplicates
LucasBerger Mar 21, 2024
f5253ef
fix: sonar
LucasBerger Mar 21, 2024
b1a440a
fix: sonar problems as possible
LucasBerger Mar 21, 2024
082b46f
fix: sonar probelms
LucasBerger Mar 21, 2024
270ce2b
fix: remove high vulnerability
LucasBerger Mar 21, 2024
d9b03d5
feat: add qaoa vrp solver
LucasBerger Mar 21, 2024
e8a820c
feat: add grover qrisp algorithm
LucasBerger Mar 22, 2024
b90244d
fix: small problem with calculation
LucasBerger Mar 22, 2024
5602575
feat: add sample for testing grovers algorithm
LucasBerger Mar 22, 2024
003f80c
some changes to make the code run locally
koalamitice May 7, 2024
72098b8
started rebasing vrp solver commit to new software architecture
koalamitice May 15, 2024
3012c5b
fixed some minor issues, merged new changes from develop
koalamitice May 28, 2024
6e821c4
added tsp example problem
koalamitice May 28, 2024
0d8b1f7
Fixed Vrp Solver, Added Vrp Test Case, Added QUBO solvers to config
koalamitice May 28, 2024
2bdfe0c
Added Test Cases for QUBO Solver
koalamitice May 28, 2024
afa9151
Continued Merging VRP Solver to new Architecture: Added new test case…
koalamitice Jun 18, 2024
7262537
save commit
koalamitice Jun 18, 2024
dd22a01
fixed clustering problem in kmeans test case
koalamitice Jun 25, 2024
73e62e6
refactoring in VRP solver, minor refactoring for sonar lint stuff in …
koalamitice Jun 25, 2024
2c518d7
reimplemented tsp qubo solver and twophase, fixed minor errors
koalamitice Jul 2, 2024
fec35df
added test cases and fixes for Qrisp and Dwave QUBO solvers. Changed …
koalamitice Jul 23, 2024
f176758
added test for twophase + d-wave
koalamitice Jul 23, 2024
7ed209f
implemented adapter to make Lucas LKH3 compatible for TSP solving
koalamitice Jul 23, 2024
0ebab42
fixed sonarqube quality issues
koalamitice Aug 12, 2024
4b6bbad
added more sonarqube problems
koalamitice Aug 12, 2024
0be2a1a
added specific version to knapsack solver
koalamitice Aug 13, 2024
292bf91
refactored solver structure, added os-specific application.properties…
koalamitice Aug 13, 2024
7c5b78b
Updated Dockerfile and install script to include new solvers and the…
koalamitice Aug 14, 2024
786ece2
Updated Readme.txt, now includes installation guide for new VRP binaries
koalamitice Aug 14, 2024
ceb1cc2
added binaries for lucas bergers vrp pipeline and lkh3 for windows, m…
koalamitice Aug 14, 2024
877a8a1
Adjusted PythonProcessRunner call in LKH solvers, they now pass the O…
koalamitice Aug 14, 2024
48a34fe
added some comments
koalamitice Aug 20, 2024
8961ffe
Fixed Style Errors, Minor Refactoring that consider comments from @El…
koalamitice Aug 21, 2024
93c75c1
feat: Allow additional http methods
Elscrux Jul 30, 2024
f9a7046
feat: Support for resetting a problem's solver
Elscrux Jul 30, 2024
8433d33
fix: Prevent updates to solving or solved problems
Elscrux Jul 30, 2024
cb33613
feat: Update state of solver when setting a solver
Elscrux Aug 13, 2024
a7ddc01
fix: Add constructor for solutions to save the problem solver name
Elscrux Aug 27, 2024
93f89d4
fix: Make internal constructors private
Elscrux Aug 27, 2024
76fcc35
fix: checkstyle
Elscrux Aug 27, 2024
f300b43
changed application.properties profile to linux (important for tests …
koalamitice Aug 27, 2024
c8acdd5
fix: application.properties loading on windows, LKH-3 cross compiled …
koalamitice Aug 27, 2024
73c114a
Fixed Qiskit QAOA solver (reimplemtented for Qiskit-Optimization-0.6)…
koalamitice Aug 29, 2024
e19712f
changed application.properties to correct system for CI pipeline
koalamitice Aug 29, 2024
8089d49
Fixed requirements.txt for new Qiskit QUBO solver
koalamitice Aug 29, 2024
4988309
adjusted requirements.txt again
koalamitice Aug 29, 2024
d4a25ba
Adjusted Qiskit MaxCut solver, now uses Qiskit-Optimization 0.6.*
koalamitice Aug 29, 2024
f67dd12
adjusted requirements.txt for Qiskit package
koalamitice Aug 29, 2024
74e9ef9
added soe debug output to workflow
koalamitice Aug 29, 2024
0fe4270
Reverted requirements.txt changes, changed gradle check to --info ins…
koalamitice Aug 29, 2024
0e1548c
trying new dependencies in requirements.txt
koalamitice Aug 29, 2024
5f25433
Removed dependecy to specific qiskit version, updated maxcut solver t…
koalamitice Aug 30, 2024
227581f
Changed Debugging prints, added wait in testcase to check for race co…
koalamitice Aug 30, 2024
f676552
Added Mising @BeforeEach to beforeEach method
koalamitice Aug 30, 2024
42cd354
fix: Support no weight attribute
Elscrux Sep 3, 2024
2c734fd
Changed Readme
koalamitice Sep 3, 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
Prev Previous commit
Next Next commit
Fixed Qiskit QAOA solver (reimplemtented for Qiskit-Optimization-0.6)…
…, refactored Qrisp QAOA (was in the wrong directory)
  • Loading branch information
koalamitice committed Aug 29, 2024
commit 73c114aa563c033118ba0e8d42dcd3bb3756e3fc
125 changes: 125 additions & 0 deletions solvers/qiskit/qubo/qp_converter/QpConverter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import re

from qiskit_optimization import QuadraticProgram

def parse_lp_file(file_path):
# Read the LP file
with open(file_path, 'r') as file:
lines = file.readlines()

# Initialize components for parsing
objective_sense = 'minimize' # default
objective = ''
constraints = []
variable_types = {}
in_objective_section = False
in_constraints_section = False
in_binary_section = False

# Parsing logic
for line in lines:
line = line.strip()

# Objective function
if line.lower().startswith('minimize') or line.lower().startswith('maximize'):
in_objective_section = True
objective_sense = line.split()[0].lower()
continue

if in_objective_section and (line.lower().startswith('subject to') or line.lower().startswith('binary')):
in_objective_section = False
continue

if in_objective_section:
objective += line
continue

# Constraints (no constraints in this example, but you may extend it later)
if line.lower().startswith('subject to'):
in_constraints_section = True
continue
elif in_constraints_section and line.lower().startswith('binary'):
in_constraints_section = False

# Binary variables
if line.lower().startswith('binary'):
in_binary_section = True
continue

if in_binary_section:
variables = line.split()
for var in variables:
variable_types[var] = 'binary'

return objective_sense, objective, constraints, variable_types


def parse_objective(objective_str):
""" Parse the objective function to extract linear and quadratic coefficients """
# Remove the 'obj:' prefix
objective_str = re.sub(r'^obj:\s*', '', objective_str)

# Extract and remove the division factor (e.g., "/ 2", "/ 3", "/ 10")
division_factor_match = re.search(r'/\s*([\d\.]+)', objective_str)
division_factor = float(division_factor_match.group(1)) if division_factor_match else 1.0
objective_str = re.sub(r'/\s*[\d\.]+', '', objective_str)

# Remove square brackets
objective_str = objective_str.replace('[', '').replace(']', '')

# Extract terms using regular expression
term_pattern = re.compile(r'([+-]?\s*\d*\.?\d+(?:e[+-]?\d+)?)\s*\*?\s*([\w\d]+)\s*(?:\*\s*([\w\d]+))?')
terms = term_pattern.findall(objective_str)
linear = {}
quadratic = {}

# Parse each term
for coeff_str, var1, var2 in terms:
coeff = float(coeff_str.replace(' ', '')) # Remove any spaces in coefficient

if var2: # Quadratic term
if (var1, var2) in quadratic:
quadratic[(var1, var2)] += coeff
else:
quadratic[(var1, var2)] = coeff
else: # Linear term
if var1 in linear:
linear[var1] += coeff
else:
linear[var1] = coeff

# Apply division factor
if division_factor != 1.0 and division_factor != 0:
for key in linear:
linear[key] /= division_factor
for key in quadratic:
quadratic[key] /= division_factor

return linear, quadratic


def convert_to_quadratic_program(lp_file_path):
# Parse the LP file
objective_sense, objective, constraints, variable_types = parse_lp_file(lp_file_path)

# Parse objective components
linear, quadratic = parse_objective(objective)

# Create an instance of QuadraticProgram
qp = QuadraticProgram()

# Add variables
for var in variable_types:
if variable_types[var] == 'binary':
qp.binary_var(var)

# Set the objective sense
if objective_sense == 'minimize':
qp.minimize(linear=linear, quadratic=quadratic)
else:
qp.maximize(linear=linear, quadratic=quadratic)

# Add constraints (empty in this example)
# You can extend this logic to handle any constraints

return qp
22 changes: 13 additions & 9 deletions solvers/qiskit/qubo/qubo_qiskit.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import sys
from qp_converter import QpConverter

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_algorithms import QAOA
from qiskit_algorithms.optimizers import COBYLA
from qiskit_optimization.algorithms import MinimumEigenOptimizer

if len(sys.argv) != 3:
Expand All @@ -12,16 +12,20 @@
input_path = sys.argv[1]
output_path = sys.argv[2]

qp = QuadraticProgram()
qp.read_from_lp_file(input_path)

qaoa_mes = QAOA(Sampler(), optimizer=COBYLA(), initial_point=[0.0, 1.0])
qubo = QpConverter.convert_to_quadratic_program(input_path)
# parse LP file:
print(qubo.prettyprint())

# TODO: Sampler() has to be replaces with StatevectorSampler() in newer versions.
# (currently not yet supported by qiskit-optimization)
# TODO: add a dedicated mixer
qaoa_mes = QAOA(sampler=Sampler(), optimizer=COBYLA())
qaoa = MinimumEigenOptimizer(qaoa_mes)
qaoa.solve(qubo)

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

f = open(output_path, 'w')
f.write(qaoa_result.prettyprint())
f.close()
f.close()
2 changes: 1 addition & 1 deletion solvers/qrisp/vrp/qaoa.py → solvers/qrisp/qubo/qaoa.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
create_QUBO_cost_operator,
def_backend,
)
from qrisp_solver.permutation import create_perm_specifiers, eval_perm_old
from qrisp_qubo_util.permutation import create_perm_specifiers, eval_perm_old

from qrisp import QuantumArray, QuantumFloat, QuantumVariable, cyclic_shift, h, x

Expand Down
6 changes: 3 additions & 3 deletions solvers/qrisp/vrp/grover.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

import numpy as np
from qrisp.grover import grovers_alg
from qrisp_solver.oracle import eval_distance_threshold
from qrisp_solver.permutation import create_perm_specifiers, eval_perm
from qrisp_solver.vrp import calc_paths, normalize_vrp
from qrisp_vrp_util.oracle import eval_distance_threshold
from qrisp_vrp_util.permutation import create_perm_specifiers, eval_perm
from qrisp_vrp_util.vrp import calc_paths, normalize_vrp
from tsplib95 import load
from tsplib95.models import StandardProblem

Expand Down
93 changes: 93 additions & 0 deletions solvers/qrisp/vrp/qrisp_vrp_util/permutation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import numpy as np
from qrisp import QuantumArray, QuantumFloat
from qrisp.core import demux
from qrisp.environments import invert


# Create a function that generates a state of superposition of all permutations
def swap_to_front(qa, index):
with invert():
# The keyword ctrl_method = "gray_pt" allows the controlled swaps to be synthesized
# using Margolus gates. These gates perform the same operation as a regular Toffoli
# but add a different phase for each input. This phase will not matter though,
# since it will be reverted once the ancilla values of the oracle are uncomputed.
demux(qa[0], index, qa, permit_mismatching_size=True)


def eval_perm(perm_specifiers, city_amount, qa=None):
N = len(perm_specifiers)

# To filter out the cyclic permutations, we impose that the first city is always city 0
# We will have to consider this assumption later when calculating the route distance
# by manually adding the trip distance of the first trip (from city 0) and the
# last trip (to city 0)
if qa is None:
qa = QuantumArray(
QuantumFloat(int(np.ceil(np.log2(city_amount)))), city_amount - 1
)

for i in range(city_amount - 1):
qa[i] += i + 1

for i in range(N):
swap_to_front(qa[i:], perm_specifiers[i])

return qa


def eval_perm_backward(perm_specifiers, city_amount, qa=None):
N = len(perm_specifiers)

# To filter out the cyclic permutations, we impose that the first city is always city 0
# We will have to consider this assumption later when calculating the route distance
# by manually adding the trip distance of the first trip (from city 0) and the
# last trip (to city 0)

for i in reversed(range(N)):
demux(qa[i], perm_specifiers[i], qa[i:], permit_mismatching_size=True)

for i in range(city_amount - 1):
qa[i] -= i + 1

return qa


def eval_perm_old(perm_specifiers, city_amount, qa=None):
N = len(perm_specifiers)

# To filter out the cyclic permutations, we impose that the first city is always city 0
# We will have to consider this assumption later when calculating the route distance
# by manually adding the trip distance of the first trip (from city 0) and the
# last trip (to city 0)
if qa is None:
qa = QuantumArray(QuantumFloat(int(np.ceil(np.log2(city_amount)))), city_amount)

add = np.arange(0, city_amount)

for i in range(city_amount):
qa[i] += int(add[i])

for i in range(N):
swap_to_front(qa[i:], perm_specifiers[i])

return qa


# Create function that returns QuantumFloats specifying the permutations (these will be in uniform superposition)
def create_perm_specifiers(city_amount, init_seq=None) -> list[QuantumFloat]:
perm_specifiers = []

for i in range(city_amount - 1):
qf_size = int(np.ceil(np.log2(city_amount - i)))

if i == 0:
continue

temp_qf = QuantumFloat(qf_size)

if not init_seq is None:
temp_qf[:] = init_seq[i - 1]

perm_specifiers.append(temp_qf)

return perm_specifiers
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ ProblemManager<String, String> getQuboManager(
private Set<Problem<String, String>> loadExampleProblems(ResourceProvider resourceProvider) {
try {
var problemInputStream = Objects.requireNonNull(
getClass().getResourceAsStream("linear-problem.txt"),
"linear-problem example for QUBO is unavailable!"
getClass().getResourceAsStream("quadratic-problem.txt"),
"quadratic-problem example for QUBO is unavailable!"
);
var problem = new Problem<>(QUBO);
problem.setInput(resourceProvider.readStream(problemInputStream));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class QrispQuboSolver extends QuboSolver {

@Autowired
public QrispQuboSolver(
@Value("${qrisp.directory.vrp}") String vrpPath,
@Value("${qrisp.directory.qubo}") String vrpPath,
ApplicationContext context) {
this.vrpPath = vrpPath;
this.context = context;
Expand All @@ -42,14 +42,14 @@ public Mono<Solution<String>> solve(
// it is used to prevent denial of service issues for large simulations.
// Default value is 4, higher values are possible but might take much longer to simulate.
// TODO: allow user to pass a custom gate size as a solver setting
int maxNumberOfCities = 4;
int maxNumberOfVariables = 4;

var processResult = context.getBean(
PythonProcessRunner.class,
vrpPath,
"qaoa.py",
new String[] {"%1$s", "--output-file", "%2$s",
"--size-gate", String.valueOf(maxNumberOfCities)}
"--size-gate", String.valueOf(maxNumberOfVariables)}
)
.problemFileName("problem.lp")
.solutionFileName("problem.bin")
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# default spring profile, correct one will be set during runtime (see ToolboxServerApplication.java)
# options: mac, windows, linux
spring.profiles.active=linux
spring.profiles.active=mac

working.directory=jobs
examples.directory=examples
Expand All @@ -22,6 +22,7 @@ cirq.directory.max-cut=${cirq.directory}/max-cut

qrisp.directory=${solvers.directory}/qrisp
qrisp.directory.vrp=${qrisp.directory}/vrp
qrisp.directory.qubo=${qrisp.directory}/qubo

dwave.directory=${solvers.directory}/dwave
dwave.directory.qubo=${dwave.directory}/qubo
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Minimize
obj: 0 + [ -32.984845004941285 x1 * x1 + 32.984845004941285 x1 * x2 + 32.984845004941285 x1 * x3 + 8.246211251235321 x1 * x4 - 32.984845004941285 x2 * x2 + 8.246211251235321 x2 * x3 + 32.984845004941285 x2 * x4 - 32.984845004941285 x3 * x3 + 32.984845004941285 x3 * x4 - 32.984845004941285 x4 * x4 ] / 2

Subject To

Binary
x1 x2 x3 x4
Loading