Skip to content
Merged
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
9d5f0d7
chore: adjust to new application.properties layout
Elscrux Apr 22, 2025
0ed292f
feat: Add molecule energy simulator
Elscrux Feb 10, 2025
e6eb5e5
refactor: Rename from hydrogen to molecule energy
Elscrux Feb 13, 2025
dcfeaf4
feat: Add note about molecule format
Elscrux Feb 13, 2025
471fbaa
feat: Add molecule energy demonstrator description
Elscrux Feb 13, 2025
9824832
chore: Change arguments to singular argument
Elscrux Mar 6, 2025
add7460
chore: Use updated application.properties and venv
Elscrux Apr 22, 2025
e82c139
refactor: Move requirements.txt to solver directory to follow the new…
Elscrux Apr 22, 2025
2d0521e
chore: Remove unused imports
Elscrux Apr 29, 2025
45c8311
chore: Change exception type
Elscrux Apr 29, 2025
24f5340
chore: Move imports up
Elscrux May 6, 2025
5666829
chore: fixate python requirement versions based on report in https://…
Elscrux May 30, 2025
03df7f6
chore: remove redundant assignment of optimizer
Elscrux May 30, 2025
0c41bf5
test: adapt CplexMipDemonstratorTest to general DemonstratorTest
Elscrux May 30, 2025
544c31b
chore: remove old debug command
Elscrux Jun 3, 2025
5e78b31
fix: put molecule argument in quotes
Elscrux Jun 3, 2025
e124884
chore: update build file to remove syntax deprecated in gradle v9
Elscrux Jun 3, 2025
bd6a8f7
feat: add detailed report of used arguments
Elscrux Jun 3, 2025
3730ba4
fix: remove prints from script as they also end up in the solution re…
Elscrux Jun 3, 2025
2811a1f
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.1'
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 @@ -23,10 +23,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.materialsimulation=materialsimulationpath.qiskit.materialsimulation=${path.qiskit}/${name.qiskit.materialsimulation}/material_simulation_qiskit.pyvenv.qiskit.materialsimulation=${name.solvers}_${name.qiskit}_${name.qiskit.materialsimulation}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.materialsimulation=materialsimulationpath.qiskit.materialsimulation=${path.qiskit}/${name.qiskit.materialsimulation}/material_simulation_qiskit.pyvenv.qiskit.materialsimulation=${name.solvers}_${name.qiskit}_${name.qiskit.materialsimulation}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