Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1f8fc9b
chore: adjust to new application.properties layout
Elscrux Apr 22, 2025
f59035d
feat: Add molecule energy simulator
Elscrux Feb 10, 2025
8649ff2
refactor: Rename from hydrogen to molecule energy
Elscrux Feb 13, 2025
7505df1
feat: Add note about molecule format
Elscrux Feb 13, 2025
623c720
feat: Add molecule energy demonstrator description
Elscrux Feb 13, 2025
0a0a49a
chore: Change arguments to singular argument
Elscrux Mar 6, 2025
36692a5
chore: Use updated application.properties and venv
Elscrux Apr 22, 2025
2409ecf
refactor: Move requirements.txt to solver directory to follow the new…
Elscrux Apr 22, 2025
3a15690
chore: Remove unused imports
Elscrux Apr 29, 2025
24ec469
chore: Change exception type
Elscrux Apr 29, 2025
2b19648
chore: Move imports up
Elscrux May 6, 2025
e17bf15
chore: fixate python requirement versions based on report in https://…
Elscrux May 30, 2025
7c4d29f
chore: remove redundant assignment of optimizer
Elscrux May 30, 2025
9198ebf
test: adapt CplexMipDemonstratorTest to general DemonstratorTest
Elscrux May 30, 2025
a07a76a
chore: remove old debug command
Elscrux Jun 3, 2025
6fa2f8b
fix: put molecule argument in quotes
Elscrux Jun 3, 2025
c19b3f2
chore: update build file to remove syntax deprecated in gradle v9
Elscrux Jun 3, 2025
5e3cb4b
feat: add detailed report of used arguments
Elscrux Jun 3, 2025
cfe5e9c
fix: remove prints from script as they also end up in the solution re…
Elscrux Jun 3, 2025
bc474be
test: increase timeout of timeouted tests
Elscrux Jun 3, 2025
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
11 changes: 6 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ plugins {

group = 'edu.kit.provideq'
version = '0.4.0'
sourceCompatibility = '17'

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url = 'https://jitpack.io' }
}

dependencies {
Expand All @@ -35,9 +39,6 @@ tasks.named('test') {
useJUnitPlatform()
}

// set Java language level
targetCompatibility = JavaVersion.VERSION_17

tasks.withType(JavaCompile).configureEach {
// treat "unchecked" warnings as errors
options.compilerArgs << '-Xlint:unchecked'
Expand Down
113 changes: 113 additions & 0 deletions demonstrators/qiskit/molecule-energy/molecule-energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from qiskit import QuantumCircuit
from qiskit_algorithms import VQE
from qiskit_algorithms.optimizers import L_BFGS_B, SLSQP
from qiskit.circuit.library import TwoLocal
from qiskit_nature.second_q.algorithms import GroundStateEigensolver
from qiskit_nature.second_q.circuit.library import HartreeFock, UCCSD
from qiskit_nature.second_q.drivers import PySCFDriver
from qiskit_nature.second_q.mappers import JordanWignerMapper, ParityMapper
from qiskit.primitives import Estimator
import matplotlib.pyplot as plt
from io import StringIO
import numpy as np
import sys

arg_count = len(sys.argv) - 1
if arg_count != 1:
raise ValueError(f'This script expects exactly 1 argument: the molecule, but got {arg_count}: {sys.argv[1:]}')
molecule = sys.argv[1]

driver = PySCFDriver(atom=molecule)
problem = driver.run()

mapper = ParityMapper(num_particles=problem.num_particles)

optimizer = L_BFGS_B()

estimator = Estimator()

ansatz = UCCSD(
problem.num_spatial_orbitals,
problem.num_particles,
mapper,
initial_state=HartreeFock(
problem.num_spatial_orbitals,
problem.num_particles,
mapper,
),
)

vqe = VQE(estimator, ansatz, optimizer)
vqe.initial_point = [0] * ansatz.num_parameters

algorithm = GroundStateEigensolver(mapper, vqe)

electronic_structure_result = algorithm.solve(problem)
electronic_structure_result.formatting_precision = 6

driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.74279')
problem = driver.run()

mapper = JordanWignerMapper()

optimizer = SLSQP(maxiter=10000, ftol=1e-9)

estimator = Estimator()

var_forms = [['ry', 'rz'], 'ry']
entanglements = ['full', 'linear']
entanglement_blocks = ['cx', 'cz', ['cx', 'cz']]
depths = list(range(1, 11))

reference_circuit = QuantumCircuit(4)
reference_circuit.x(0)
reference_circuit.x(2)

results = np.zeros((len(depths), len(entanglements), len(var_forms), len(entanglement_blocks)))

for i, d in enumerate(depths):
for j, e in enumerate(entanglements):
for k, vf in enumerate(var_forms):
for l, eb in enumerate(entanglement_blocks):
variational_form = TwoLocal(4, rotation_blocks=vf, entanglement_blocks=eb, entanglement=e, reps=d)

ansatz = reference_circuit.compose(variational_form)

vqe = VQE(estimator, ansatz, optimizer)
vqe.initial_point = [0] * ansatz.num_parameters

algorithm = GroundStateEigensolver(mapper, vqe)

electronic_structure_result = algorithm.solve(problem)

results[i, j, k, l] = electronic_structure_result.total_energies[0]

fig1, axs1 = plt.subplots(2, 3, sharey=True, sharex=True)
fig2, axs2 = plt.subplots(2, 3, sharey=True, sharex=True)

fig1.supxlabel('Depth')
fig1.supylabel('Estimated ground state energy')
fig2.supxlabel('Depth')
fig2.supylabel('Estimated ground state energy')

for j, e in enumerate(entanglements):
for l, eb in enumerate(entanglement_blocks):
axs1[j, l].plot(depths, results[:, j, 0, l])
axs1[j, l].set_title(f'{e}, ryrz, {eb}')
axs1[j, l].text(0.90, 0.75, f'Min: {np.min(results[:, j, 0, l]):.3f}')

for j, e in enumerate(entanglements):
for l, eb in enumerate(entanglement_blocks):
axs2[j, l].plot(depths, results[:, j, 1, l])
axs2[j, l].set_title(f'{e}, ry, {eb}')
axs2[j, l].text(0.90, 0.75, f'Min: {np.min(results[:, j, 1, l]):.3f}')


def print_fig(fig):
string_io = StringIO()
fig.savefig(string_io, format='svg')
print(string_io.getvalue())


print_fig(fig1)
print_fig(fig2)
14 changes: 14 additions & 0 deletions demonstrators/qiskit/molecule-energy/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This file describes the python package requirements for all Qiskit demonstrator scripts
# supported by ProvideQ

# required for molecule energy solver
qiskit==1.1.0
qiskit-aer==0.14.2
qiskit-algorithms==0.3.0
qiskit-ibm-runtime==0.25.0
qiskit-machine-learning==0.7.2
qiskit-nature==0.7.2
qiskit-nature-pyscf==0.4.0
qiskit-qasm3-import==0.5.0
qiskit-transpiler-service==0.4.5
matplotlib==3.9.2
2 changes: 1 addition & 1 deletion solvers/custom/hs-knapsack/knapsack.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from knapsack01 import HSKnapsack

if len(sys.argv) != 3:
raise TypeError('This script expects exactly 2 arguments. Input file (argument 1) and output file (argument 2).')
raise ValueError('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]
Expand Down
2 changes: 1 addition & 1 deletion solvers/qiskit/max-cut/maxCut_qiskit.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


#if len(sys.argv) != 3:
# raise TypeError('This script expects exactly 2 arguments. Input file (argument 1) and output file (argument 2).')
# raise ValueError('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]
Expand Down
2 changes: 1 addition & 1 deletion solvers/qiskit/qubo/qubo_qiskit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from qiskit_optimization.algorithms import MinimumEigenOptimizer

if len(sys.argv) != 3:
raise TypeError('This script expects exactly 2 arguments. Input file (argument 1) and output file (argument 2).')
raise ValueError('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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ public class DemonstratorConfiguration {

@Bean
ProblemManager<String, String> getDemonstratorManager(
CplexMipDemonstrator cplexMipDemonstrator
CplexMipDemonstrator cplexMipDemonstrator,
MoleculeEnergySimulator moleculeEnergySimulator
) {
return new ProblemManager<>(DEMONSTRATOR,
Set.of(cplexMipDemonstrator),
Set.of(cplexMipDemonstrator, moleculeEnergySimulator),
Set.of(new Problem<>(DEMONSTRATOR)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package edu.kit.provideq.toolbox.demonstrators;

import edu.kit.provideq.toolbox.Solution;
import edu.kit.provideq.toolbox.meta.SolvingProperties;
import edu.kit.provideq.toolbox.meta.SubRoutineResolver;
import edu.kit.provideq.toolbox.meta.setting.SolverSetting;
import edu.kit.provideq.toolbox.meta.setting.basic.TextSetting;
import edu.kit.provideq.toolbox.process.PythonProcessRunner;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
* Demonstrator for the Molecule Energy simulation.
* Note that its python dependencies can only be installed on Linux and macOS.
* Based on this <a href="https://github.com/qiskit-community/qiskit-community-tutorials/blob/master/chemistry/h2_var_forms.ipynb">Jupyter Notebook</a>
*/
@Component
public class MoleculeEnergySimulator implements Demonstrator {
private final String scriptPath;
private final String venv;
private final ApplicationContext context;

private static final String SETTING_MOLECULE = "Molecule";
private static final String DEFAULT_MOLECULE = "H .0 .0 .0; H .0 .0 0.74279";

@Autowired
public MoleculeEnergySimulator(
@Value("${path.demonstrators.qiskit.molecule-energy}") String scriptPath,
@Value("${venv.demonstrators.qiskit.molecule-energy}") String venv,
ApplicationContext context) {
this.scriptPath = scriptPath;
this.venv = venv;
this.context = context;
}

@Override
public String getName() {
return "Molecule Energy Simulator";
}

@Override
public String getDescription() {
return "Computes the ground state energy for a given molecule using VQE algorithm.";
}

@Override
public List<SolverSetting> getSolverSettings() {
return List.of(
new TextSetting(
false,
SETTING_MOLECULE,
"The molecule to be simulated in XYZ format - a di-hydrogen molecule by default",
DEFAULT_MOLECULE
)
);
}

@Override
public Mono<Solution<String>> solve(String input, SubRoutineResolver subRoutineResolver,
SolvingProperties properties) {
var solution = new Solution<>(this);

var molecule = properties.<TextSetting>getSetting(SETTING_MOLECULE)
.map(TextSetting::getText)
.orElse(DEFAULT_MOLECULE);

var processResult = context
.getBean(PythonProcessRunner.class, scriptPath, venv)
.withArguments('"' + molecule + '"')
.readOutputString()
.run(getProblemType(), solution.getId());

return Mono.just(processResult.applyTo(solution));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,6 @@ protected <T> ProcessRunnerExecutor<T> getExecutor(
int processExitCode;
try {
processBuilder.directory(new File(System.getProperty("user.dir")));
String command =
processBuilder.command().stream().reduce("", (a, b) -> a + " |break| " + b);
Process process = processBuilder.start();

processOutput = resourceProvider.readStream(process.inputReader());
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# default spring profile, correct one will be set during runtime (see ToolboxServerApplication.java)# options: mac, windows, linuxspring.profiles.active=linuxspringdoc.swagger-ui.operationsSorter=alphaspringdoc.swagger-ui.tagsSorter=alphaworking.directory=jobsexamples.directory=examplesspringdoc.swagger-ui.path=/# Solversname.solvers=solvers# Non OS-specific solvers: (typically GAMS and Python)name.gams=gamspath.gams=${name.solvers}/${name.gams}name.gams.max-cut=max-cutpath.gams.max-cut=${path.gams}/${name.gams.max-cut}/maxcut.gmsname.gams.sat=satpath.gams.sat=${path.gams}/${name.gams.sat}/sat.gmsname.qiskit=qiskitpath.qiskit=${name.solvers}/${name.qiskit}name.qiskit.knapsack=knapsackpath.qiskit.knapsack=${path.qiskit}/${name.qiskit.knapsack}/knapsack_qiskit.pyvenv.qiskit.knapsack=${name.solvers}_${name.qiskit}_${name.qiskit.knapsack}name.qiskit.max-cut=max-cutpath.qiskit.max-cut=${path.qiskit}/${name.qiskit.max-cut}/maxCut_qiskit.pyvenv.qiskit.max-cut=${name.solvers}_${name.qiskit}_${name.qiskit.max-cut}name.qiskit.qubo=qubopath.qiskit.qubo=${path.qiskit}/${name.qiskit.qubo}/qubo_qiskit.pyvenv.qiskit.qubo=${name.solvers}_${name.qiskit}_${name.qiskit.qubo}name.cirq=cirqpath.cirq=${name.solvers}/${name.cirq}name.cirq.max-cut=max-cutpath.cirq.max-cut=${path.cirq}/${name.cirq.max-cut}/max_cut_cirq.pyvenv.cirq.max-cut=${name.solvers}_${name.cirq}_${name.cirq.max-cut}name.qrisp=qrisppath.qrisp=${name.solvers}/${name.qrisp}name.qrisp.vrp=vrppath.qrisp.vrp=${path.qrisp}/${name.qrisp.vrp}/grover.pyvenv.qrisp.vrp=${name.solvers}_${name.qrisp}_${name.qrisp.vrp}name.qrisp.qubo=qubopath.qrisp.qubo=${path.qrisp}/${name.qrisp.qubo}/qaoa.pyvenv.qrisp.qubo=${name.solvers}_${name.qrisp}_${name.qrisp.qubo}name.qrisp.sat=satpath.qrisp.sat.grover=${path.qrisp}/${name.qrisp.sat}/grover.pypath.qrisp.sat.exact=${path.qrisp}/${name.qrisp.sat}/exact_grover.pyvenv.qrisp.sat=${name.solvers}_${name.qrisp}_${name.qrisp.sat}name.dwave=dwavepath.dwave=${name.solvers}/${name.dwave}name.dwave.qubo=qubopath.dwave.qubo=${path.dwave}/${name.dwave.qubo}/main.pyvenv.dwave.qubo=${name.solvers}_${name.dwave}_${name.dwave.qubo}# Non OS-specific custom solvers: (solvers that are not part of a framework)name.custom=custompath.custom=${name.solvers}/${name.custom}name.custom.hs-knapsack=hs-knapsackpath.custom.hs-knapsack=${path.custom}/${name.custom.hs-knapsack}/knapsack.pyvenv.custom.hs-knapsack=${name.solvers}_${name.custom}_${name.custom.hs-knapsack}name.custom.lkh=lkhpath.custom.lkh=${path.custom}/${name.custom.lkh}/vrp_lkh.pyvenv.custom.lkh=${name.solvers}_${name.custom}_${name.custom.lkh}name.custom.berger-vrp=berger-vrpname.custom.sharp-sat-bruteforce=sharp-sat-bruteforcepath.custom.sharp-sat-bruteforce=${path.custom}/${name.custom.sharp-sat-bruteforce}/exact-solution-counter.pyvenv.custom.sharp-sat-bruteforce=${name.solvers}_${name.custom}_${name.custom.sharp-sat-bruteforce}name.custom.sharp-sat-ganak=sharp-sat-ganakvenv.custom.sharp-sat-ganak=${name.solvers}_${name.custom}_${name.custom.sharp-sat-ganak}# Demonstratorsname.demonstrators=demonstratorsname.demonstrators.cplex=cplexpath.demonstrators.cplex=${name.demonstrators}/${name.demonstrators.cplex}name.demonstrators.cplex.mip=mip-solverpath.demonstrators.cplex.mip=${path.demonstrators.cplex}/${name.demonstrators.cplex.mip}/mip-solver.pyvenv.demonstrators.cplex.mip=${name.demonstrators}_${name.demonstrators.cplex}_${name.demonstrators.cplex.mip}
# default spring profile, correct one will be set during runtime (see ToolboxServerApplication.java)# options: mac, windows, linuxspring.profiles.active=linuxspringdoc.swagger-ui.operationsSorter=alphaspringdoc.swagger-ui.tagsSorter=alphaworking.directory=jobsexamples.directory=examplesspringdoc.swagger-ui.path=/# Solversname.solvers=solvers# Non OS-specific solvers: (typically GAMS and Python)name.gams=gamspath.gams=${name.solvers}/${name.gams}name.gams.max-cut=max-cutpath.gams.max-cut=${path.gams}/${name.gams.max-cut}/maxcut.gmsname.gams.sat=satpath.gams.sat=${path.gams}/${name.gams.sat}/sat.gmsname.qiskit=qiskitpath.qiskit=${name.solvers}/${name.qiskit}name.qiskit.knapsack=knapsackpath.qiskit.knapsack=${path.qiskit}/${name.qiskit.knapsack}/knapsack_qiskit.pyvenv.qiskit.knapsack=${name.solvers}_${name.qiskit}_${name.qiskit.knapsack}name.qiskit.max-cut=max-cutpath.qiskit.max-cut=${path.qiskit}/${name.qiskit.max-cut}/maxCut_qiskit.pyvenv.qiskit.max-cut=${name.solvers}_${name.qiskit}_${name.qiskit.max-cut}name.qiskit.qubo=qubopath.qiskit.qubo=${path.qiskit}/${name.qiskit.qubo}/qubo_qiskit.pyvenv.qiskit.qubo=${name.solvers}_${name.qiskit}_${name.qiskit.qubo}name.cirq=cirqpath.cirq=${name.solvers}/${name.cirq}name.cirq.max-cut=max-cutpath.cirq.max-cut=${path.cirq}/${name.cirq.max-cut}/max_cut_cirq.pyvenv.cirq.max-cut=${name.solvers}_${name.cirq}_${name.cirq.max-cut}name.qrisp=qrisppath.qrisp=${name.solvers}/${name.qrisp}name.qrisp.vrp=vrppath.qrisp.vrp=${path.qrisp}/${name.qrisp.vrp}/grover.pyvenv.qrisp.vrp=${name.solvers}_${name.qrisp}_${name.qrisp.vrp}name.qrisp.qubo=qubopath.qrisp.qubo=${path.qrisp}/${name.qrisp.qubo}/qaoa.pyvenv.qrisp.qubo=${name.solvers}_${name.qrisp}_${name.qrisp.qubo}name.qrisp.sat=satpath.qrisp.sat.grover=${path.qrisp}/${name.qrisp.sat}/grover.pypath.qrisp.sat.exact=${path.qrisp}/${name.qrisp.sat}/exact_grover.pyvenv.qrisp.sat=${name.solvers}_${name.qrisp}_${name.qrisp.sat}name.dwave=dwavepath.dwave=${name.solvers}/${name.dwave}name.dwave.qubo=qubopath.dwave.qubo=${path.dwave}/${name.dwave.qubo}/main.pyvenv.dwave.qubo=${name.solvers}_${name.dwave}_${name.dwave.qubo}# Non OS-specific custom solvers: (solvers that are not part of a framework)name.custom=custompath.custom=${name.solvers}/${name.custom}name.custom.hs-knapsack=hs-knapsackpath.custom.hs-knapsack=${path.custom}/${name.custom.hs-knapsack}/knapsack.pyvenv.custom.hs-knapsack=${name.solvers}_${name.custom}_${name.custom.hs-knapsack}name.custom.lkh=lkhpath.custom.lkh=${path.custom}/${name.custom.lkh}/vrp_lkh.pyvenv.custom.lkh=${name.solvers}_${name.custom}_${name.custom.lkh}name.custom.berger-vrp=berger-vrpname.custom.sharp-sat-bruteforce=sharp-sat-bruteforcepath.custom.sharp-sat-bruteforce=${path.custom}/${name.custom.sharp-sat-bruteforce}/exact-solution-counter.pyvenv.custom.sharp-sat-bruteforce=${name.solvers}_${name.custom}_${name.custom.sharp-sat-bruteforce}name.custom.sharp-sat-ganak=sharp-sat-ganakvenv.custom.sharp-sat-ganak=${name.solvers}_${name.custom}_${name.custom.sharp-sat-ganak}# Demonstratorsname.demonstrators=demonstratorsname.demonstrators.cplex=cplexpath.demonstrators.cplex=${name.demonstrators}/${name.demonstrators.cplex}name.demonstrators.cplex.mip=mip-solverpath.demonstrators.cplex.mip=${path.demonstrators.cplex}/${name.demonstrators.cplex.mip}/mip-solver.pyvenv.demonstrators.cplex.mip=${name.demonstrators}_${name.demonstrators.cplex}_${name.demonstrators.cplex.mip}name.demonstrators.qiskit=qiskitpath.demonstrators.qiskit=${name.demonstrators}/${name.demonstrators.qiskit}name.demonstrators.qiskit.molecule-energy=molecule-energypath.demonstrators.qiskit.molecule-energy=${path.demonstrators.qiskit}/${name.demonstrators.qiskit.molecule-energy}/molecule-energy.pyvenv.demonstrators.qiskit.molecule-energy=${name.demonstrators}_${name.demonstrators.qiskit}_${name.demonstrators.qiskit.molecule-energy}
Expand Down

This file was deleted.

Loading