diff --git a/solvers/circuitprocessing/circuitexecution/executor.py b/solvers/circuitprocessing/circuitexecution/executor.py new file mode 100644 index 00000000..379288f1 --- /dev/null +++ b/solvers/circuitprocessing/circuitexecution/executor.py @@ -0,0 +1,40 @@ +import sys +from pytket.qasm import circuit_from_qasm_str + +input_path = sys.argv[1] +num_runs = int(sys.argv[2]) +backend_name = sys.argv[3] + +with open(input_path, 'r') as input_file: + text = input_file.read() + +try: + circuit = circuit_from_qasm_str(text) +except Exception as e: + print("Was not able to convert to OpenQASM: ", e) + sys.exit(1) + +if backend_name == "aer": + from pytket.extensions.qiskit import AerBackend + backend = AerBackend() +elif backend_name == "qulacs": + from pytket.extensions.qulacs import QulacsBackend + backend = QulacsBackend() +elif backend_name == "aer_noisy": + from pytket.extensions.qiskit import AerBackend + from qiskit_aer.noise import NoiseModel + from qiskit_aer.noise.errors import depolarizing_error + # https://docs.quantinuum.com/tket/user-guide/manual/manual_noise.html + noise_model = NoiseModel() + noise_model.add_readout_error([[0.9, 0.1], [0.1, 0.9]], [0]) + noise_model.add_readout_error([[0.95, 0.05], [0.05, 0.95]], [1]) + noise_model.add_quantum_error(depolarizing_error(0.1, 2), ["cx"], [0, 1]) + backend = AerBackend(noise_model) +else: + print(f"Unknown backend: {backend_name}", file=sys.stderr) + sys.exit(1) + +c = backend.get_compiled_circuit(circuit) +handle = backend.process_circuit(c, n_shots=num_runs) +counts = backend.get_result(handle).get_counts() +print(counts) diff --git a/solvers/circuitprocessing/circuitexecution/requirements.txt b/solvers/circuitprocessing/circuitexecution/requirements.txt new file mode 100644 index 00000000..46f05119 --- /dev/null +++ b/solvers/circuitprocessing/circuitexecution/requirements.txt @@ -0,0 +1,3 @@ +pytket +pytket-qiskit +# pytket-qulacs \ No newline at end of file diff --git a/solvers/circuitprocessing/circuitoptimizing/decompose-multi-cx/decompose_multi_cx_optimizer.py b/solvers/circuitprocessing/circuitoptimizing/decompose-multi-cx/decompose_multi_cx_optimizer.py new file mode 100644 index 00000000..3378a019 --- /dev/null +++ b/solvers/circuitprocessing/circuitoptimizing/decompose-multi-cx/decompose_multi_cx_optimizer.py @@ -0,0 +1,25 @@ +import sys +from pytket.qasm import circuit_from_qasm_str, circuit_to_qasm_str +from pytket.predicates import CompilationUnit +from pytket.passes import DecomposeMultiQubitsCX + +input_path = sys.argv[1] + +# read input from file +with open(input_path, 'r') as input_file: + text = input_file.read() + +input_circuit = text + +try: + circuit = circuit_from_qasm_str(input_circuit) +except Exception as e: + print("Was not able to convert to OpenQASM: ", e) + sys.exit(1) + +pass1 = DecomposeMultiQubitsCX() +cu = CompilationUnit(circuit) +pass1.apply(cu) + +print(circuit_to_qasm_str(cu.circuit)) + diff --git a/solvers/circuitprocessing/circuitoptimizing/remove-redundancies/remove_redundancies_optimizer.py b/solvers/circuitprocessing/circuitoptimizing/remove-redundancies/remove_redundancies_optimizer.py new file mode 100644 index 00000000..a238a84a --- /dev/null +++ b/solvers/circuitprocessing/circuitoptimizing/remove-redundancies/remove_redundancies_optimizer.py @@ -0,0 +1,24 @@ +import sys +from pytket.qasm import circuit_from_qasm_str, circuit_to_qasm_str +from pytket.predicates import CompilationUnit +from pytket.passes import RemoveRedundancies + +input_path = sys.argv[1] + +# read input from file +with open(input_path, 'r') as input_file: + text = input_file.read() + +input_circuit = text + +try: + circuit = circuit_from_qasm_str(input_circuit) +except Exception as e: + print("Was not able to convert to OpenQASM: ", e) + sys.exit(1) + +pass1 = RemoveRedundancies() +cu = CompilationUnit(circuit) +pass1.apply(cu) + +print(circuit_to_qasm_str(cu.circuit)) \ No newline at end of file diff --git a/solvers/circuitprocessing/circuitoptimizing/requirements.txt b/solvers/circuitprocessing/circuitoptimizing/requirements.txt new file mode 100644 index 00000000..f32bd3e4 --- /dev/null +++ b/solvers/circuitprocessing/circuitoptimizing/requirements.txt @@ -0,0 +1 @@ +pytket \ No newline at end of file diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/CircuitProcessingConfiguration.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/CircuitProcessingConfiguration.java new file mode 100644 index 00000000..1011d7fb --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/CircuitProcessingConfiguration.java @@ -0,0 +1,62 @@ +package edu.kit.provideq.toolbox.circuit.processing; + +import edu.kit.provideq.toolbox.ResourceProvider; +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToExecutionSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToMitigationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToOptimizationSolver; +import edu.kit.provideq.toolbox.exception.MissingExampleException; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemType; +import java.io.IOException; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CircuitProcessingConfiguration { + public static final ProblemType CIRCUIT_PROCESSING = new ProblemType<>( + "circuit-processing", + "A quantum circuit processing problem that routes a QASM circuit through optimization, " + + "error mitigation, or execution.", + String.class, + String.class + ); + + @Bean + ProblemManager getCircuitProcessingManager( + ResourceProvider provider, + MoveToExecutionSolver moveToExecutionSolver, + MoveToOptimizationSolver moveToOptimizationSolver, + MoveToMitigationSolver moveToMitigationSolver + ) { + return new ProblemManager<>( + CIRCUIT_PROCESSING, + Set.of( + moveToExecutionSolver, + moveToOptimizationSolver, + moveToMitigationSolver + ), + loadExampleProblems(provider) + ); + } + + private Set> loadExampleProblems(ResourceProvider provider) { + try { + String[] problemNames = new String[] {"bell-state.qasm", "cswap.qasm"}; + var problemSet = new HashSet>(); + for (var problemName : problemNames) { + var problemStream = Objects.requireNonNull( + getClass().getResourceAsStream(problemName), "Problem " + problemName + " not found"); + var problem = new Problem<>(CIRCUIT_PROCESSING); + problem.setInput(provider.readStream(problemStream)); + problemSet.add(problem); + } + return problemSet; + } catch (IOException e) { + throw new MissingExampleException(CIRCUIT_PROCESSING, e); + } + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/CircuitProcessingSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/CircuitProcessingSolver.java new file mode 100644 index 00000000..9d00eff2 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/CircuitProcessingSolver.java @@ -0,0 +1,20 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver; + +import edu.kit.provideq.toolbox.circuit.processing.CircuitProcessingConfiguration; +import edu.kit.provideq.toolbox.meta.ProblemSolver; +import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; + +public abstract class CircuitProcessingSolver implements ProblemSolver { + public static final SubRoutineDefinition CIRCUIT_PROCESSING_SUBROUTINE = + new SubRoutineDefinition<>( + CircuitProcessingConfiguration.CIRCUIT_PROCESSING, + "Creates a circuit processing solver", + true + ); + + @Override + public ProblemType getProblemType() { + return CircuitProcessingConfiguration.CIRCUIT_PROCESSING; + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToExecutionSolver.java new file mode 100644 index 00000000..023cd7b8 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToExecutionSolver.java @@ -0,0 +1,58 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.SolutionStatus; +import edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutionResult; +import edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutorConfiguration; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; +import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import java.util.List; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +public class MoveToExecutionSolver extends CircuitProcessingSolver { + private static final SubRoutineDefinition EXECUTOR_SUBROUTINE = + new SubRoutineDefinition<>( + ExecutorConfiguration.EXECUTOR_CONFIG, + "Creates a execution solver", + true + ); + + @Override + public String getName() { + return "Execute QASM Code"; + } + + @Override + public String getDescription() { + return "Move QASM input to the executors"; + } + + @Override + public List> getSubRoutines() { + return List.of(EXECUTOR_SUBROUTINE); + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + return subRoutineResolver.runSubRoutine(EXECUTOR_SUBROUTINE, input) + .map(executionResultSolution -> { + Solution solution = new Solution<>(this); + SolutionStatus status = executionResultSolution.getStatus(); + if (status == SolutionStatus.ERROR) { + solution.fail(); + solution.setDebugData(executionResultSolution.getDebugData()); + return solution; + } + solution.complete(); + solution.setSolutionData(executionResultSolution.getSolutionData().toString()); + return solution; + }); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToMitigationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToMitigationSolver.java new file mode 100644 index 00000000..fcfe9892 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToMitigationSolver.java @@ -0,0 +1,44 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationConfiguration; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; +import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import java.util.List; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +public class MoveToMitigationSolver extends CircuitProcessingSolver { + private static final SubRoutineDefinition MITIGATOR_SUBROUTINE = + new SubRoutineDefinition<>( + ErrorMitigationConfiguration.MITIGATION_CONFIG, + "Creates a mitigation solver", + true + ); + + @Override + public String getName() { + return "Mitigate QASM Code Errors"; + } + + @Override + public String getDescription() { + return "Move QASM input to the error mitigators"; + } + + @Override + public List> getSubRoutines() { + return List.of(MITIGATOR_SUBROUTINE); + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + return subRoutineResolver.runSubRoutine(MITIGATOR_SUBROUTINE, input); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToOptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToOptimizationSolver.java new file mode 100644 index 00000000..794e7b68 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/MoveToOptimizationSolver.java @@ -0,0 +1,44 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.circuit.processing.solver.optimization.OptimizationConfiguration; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; +import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import java.util.List; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +public class MoveToOptimizationSolver extends CircuitProcessingSolver { + private static final SubRoutineDefinition OPTIMIZER_SUBROUTINE = + new SubRoutineDefinition<>( + OptimizationConfiguration.OPTIMIZATION_CONFIG, + "Creates a optimization solver", + true + ); + + @Override + public String getName() { + return "Optimize QASM Code"; + } + + @Override + public String getDescription() { + return "Move QASM input to the optimizers"; + } + + @Override + public List> getSubRoutines() { + return List.of(OPTIMIZER_SUBROUTINE); + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + return subRoutineResolver.runSubRoutine(OPTIMIZER_SUBROUTINE, input); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionResult.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionResult.java new file mode 100644 index 00000000..4751c2b7 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionResult.java @@ -0,0 +1,13 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.executor; + +import java.util.Optional; + +public record ExecutionResult(Optional resultString, Optional circuit) { + public boolean hasResult() { + return resultString.isPresent(); + } + + public boolean hasCircuit() { + return circuit.isPresent(); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionSolver.java new file mode 100644 index 00000000..3b216c5e --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutionSolver.java @@ -0,0 +1,146 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.executor; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.ProblemSolver; +import edu.kit.provideq.toolbox.meta.ProblemType; +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.IntegerSetting; +import edu.kit.provideq.toolbox.meta.setting.basic.SelectSetting; +import edu.kit.provideq.toolbox.process.ProcessRunner; +import edu.kit.provideq.toolbox.process.PythonProcessRunner; +import java.util.List; +import java.util.Optional; +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; + +@Component +public class ExecutionSolver implements ProblemSolver { + private static final String SETTING_NUMBER_OF_SHOTS = "Number of shots"; + private static final String SETTING_SELECT_SIMULATOR = "Selected Simulator"; + private static final int DEFAULT_NUMBER_OF_SHOTS = 1024; + private static final QuantumSimulator DEFAULT_SIMULATOR = QuantumSimulator.AER; + + private final String scriptPath; + private final String venv; + private final ApplicationContext context; + + @Autowired + public ExecutionSolver( + @Value("${path.circuitprocessing.circuitexecution}") String scriptPath, + @Value("${venv.circuitprocessing.circuitexecution}") String venv, + ApplicationContext context + ) { + this.context = context; + this.venv = venv; + this.scriptPath = scriptPath; + } + + @Override + public String getName() { + return "Execute OpenQASM circuit"; + } + + @Override + public String getDescription() { + return "Execute an OpenQASM circuit"; + } + + @Override + public List getSolverSettings() { + return List.of( + new IntegerSetting( + SETTING_NUMBER_OF_SHOTS, + "The number of shots to run", + 1, + 1000000, + DEFAULT_NUMBER_OF_SHOTS), + new SelectSetting<>( + SETTING_SELECT_SIMULATOR, + "The simulator to run the code with", + List.of(QuantumSimulator.values()), + QuantumSimulator.AER, + QuantumSimulator::getValue + ) + ); + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + var solution = new Solution<>(this); + + int shotNumber = properties.getSetting(SETTING_NUMBER_OF_SHOTS) + .map(IntegerSetting::getValue) + .orElse(DEFAULT_NUMBER_OF_SHOTS); + + QuantumSimulator selectedSimulator = properties + .>getSetting(SETTING_SELECT_SIMULATOR) + .map(s -> s.getSelectedOptionT(QuantumSimulator::fromValue)) + .orElse(DEFAULT_SIMULATOR); + + var processResult = context + .getBean(PythonProcessRunner.class, scriptPath + "executor.py", venv) + .withArguments( + ProcessRunner.INPUT_FILE_PATH, + String.valueOf(shotNumber), + selectedSimulator.getBackendKey() + ) + .writeInputFile(input) + .readOutputString() + .run(getProblemType(), solution.getId()); + + if (processResult.success()) { + solution.complete(); + solution.setSolutionData(new ExecutionResult(processResult.output(), Optional.of(input))); + return Mono.just(solution); + } + solution.fail(); + processResult.errorOutput().ifPresent(solution::setDebugData); + return Mono.just(solution); + } + + @Override + public ProblemType getProblemType() { + return ExecutorConfiguration.EXECUTOR_CONFIG; + } + + enum QuantumSimulator { + AER("AerBackend", "aer"), + // PROJECTQ("ProjectQBackend", "projectq"), + QULACS("QulacsBackend", "qulacs"), + AER_NOISY("Aer Noisy Backend (max. 2 qubits)", "aer_noisy"); + + private final String value; + private final String backendKey; + + QuantumSimulator(String value, String backendKey) { + this.value = value; + this.backendKey = backendKey; + } + + public String getValue() { + return value; + } + + public String getBackendKey() { + return backendKey; + } + + public static QuantumSimulator fromValue(String value) { + for (QuantumSimulator simulator : values()) { + if (simulator.value.equals(value)) { + return simulator; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutorConfiguration.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutorConfiguration.java new file mode 100644 index 00000000..939122b7 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/executor/ExecutorConfiguration.java @@ -0,0 +1,47 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.executor; + +import edu.kit.provideq.toolbox.ResourceProvider; +import edu.kit.provideq.toolbox.exception.MissingExampleException; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemType; +import java.io.IOException; +import java.util.Objects; +import java.util.Set; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ExecutorConfiguration { + public static final ProblemType EXECUTOR_CONFIG = new ProblemType<>( + "circuit-processing-executor", + "A quantum circuit execution problem that runs a given QASM circuit on a quantum backend " + + "and returns the measurement results.", + String.class, + ExecutionResult.class + ); + + @Bean + ProblemManager getExecutorProblemManager( + ResourceProvider provider, + ExecutionSolver executionSolver + ) { + return new ProblemManager<>( + EXECUTOR_CONFIG, + Set.of(executionSolver), + loadExampleProblems(provider) + ); + } + + private Set> loadExampleProblems(ResourceProvider provider) { + try { + var problemStream = Objects.requireNonNull( + getClass().getResourceAsStream("../../bell-state.qasm"), "Problem bell-state.qasm not found"); + var problem = new Problem<>(EXECUTOR_CONFIG); + problem.setInput(provider.readStream(problemStream)); + return Set.of(problem); + } catch (IOException e) { + throw new MissingExampleException(EXECUTOR_CONFIG, e); + } + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationConfiguration.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationConfiguration.java new file mode 100644 index 00000000..f9ee685b --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationConfiguration.java @@ -0,0 +1,47 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.mitigation; + +import edu.kit.provideq.toolbox.ResourceProvider; +import edu.kit.provideq.toolbox.exception.MissingExampleException; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemType; +import java.io.IOException; +import java.util.Objects; +import java.util.Set; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ErrorMitigationConfiguration { + public static final ProblemType MITIGATION_CONFIG = new ProblemType<>( + "circuit-processing-mitigation", + "A quantum circuit error mitigation problem that applies error mitigation techniques to " + + "a given QASM circuit.", + String.class, + String.class + ); + + @Bean + ProblemManager getMitigationProblemManager( + ResourceProvider provider, + ErrorMitigationSolver errorMitigationSolver + ) { + return new ProblemManager<>( + MITIGATION_CONFIG, + Set.of(errorMitigationSolver), + loadExampleProblems(provider) + ); + } + + private Set> loadExampleProblems(ResourceProvider provider) { + try { + var problemStream = Objects.requireNonNull( + getClass().getResourceAsStream("../../bell-state.qasm"), "Problem bell-state.qasm not found"); + var problem = new Problem<>(MITIGATION_CONFIG); + problem.setInput(provider.readStream(problemStream)); + return Set.of(problem); + } catch (IOException e) { + throw new MissingExampleException(MITIGATION_CONFIG, e); + } + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationSolver.java new file mode 100644 index 00000000..6399409e --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/mitigation/ErrorMitigationSolver.java @@ -0,0 +1,40 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.mitigation; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.ProblemSolver; +import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +public class ErrorMitigationSolver implements ProblemSolver { + + @Override + public String getName() { + return "Mitigate Errors for OpenQASM"; + } + + @Override + public String getDescription() { + return "Run error mitigation strategies on an OpenQASM circuit"; + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + var solution = new Solution<>(this); + solution.setSolutionData(input); + solution.complete(); + return Mono.just(solution); + } + + @Override + public ProblemType getProblemType() { + return ErrorMitigationConfiguration.MITIGATION_CONFIG; + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationConfiguration.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationConfiguration.java new file mode 100644 index 00000000..6de1e680 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationConfiguration.java @@ -0,0 +1,47 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.optimization; + +import edu.kit.provideq.toolbox.ResourceProvider; +import edu.kit.provideq.toolbox.exception.MissingExampleException; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemType; +import java.io.IOException; +import java.util.Objects; +import java.util.Set; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OptimizationConfiguration { + public static final ProblemType OPTIMIZATION_CONFIG = new ProblemType<>( + "circuit-processing-optimization", + "A quantum circuit optimization problem that reduces gate count or circuit depth of a " + + "given QASM circuit.", + String.class, + String.class + ); + + @Bean + ProblemManager getOptimizationProblemManager( + ResourceProvider provider, + OptimizationSolver optimizationSolver + ) { + return new ProblemManager<>( + OPTIMIZATION_CONFIG, + Set.of(optimizationSolver), + loadExampleProblems(provider) + ); + } + + private Set> loadExampleProblems(ResourceProvider provider) { + try { + var problemStream = Objects.requireNonNull( + getClass().getResourceAsStream("../../bell-state.qasm"), "Problem bell-state.qasm not found"); + var problem = new Problem<>(OPTIMIZATION_CONFIG); + problem.setInput(provider.readStream(problemStream)); + return Set.of(problem); + } catch (IOException e) { + throw new MissingExampleException(OPTIMIZATION_CONFIG, e); + } + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationSolver.java new file mode 100644 index 00000000..be8d1b4d --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solver/optimization/OptimizationSolver.java @@ -0,0 +1,142 @@ +package edu.kit.provideq.toolbox.circuit.processing.solver.optimization; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.circuit.processing.solver.CircuitProcessingSolver; +import edu.kit.provideq.toolbox.meta.ProblemSolver; +import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; +import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import edu.kit.provideq.toolbox.meta.setting.SolverSetting; +import edu.kit.provideq.toolbox.meta.setting.basic.SelectSetting; +import edu.kit.provideq.toolbox.process.ProcessRunner; +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; + +@Component +public class OptimizationSolver implements ProblemSolver { + private static final String SETTING_SELECT_OPTIMIZER = "Selected Optimization Pass"; + private static final OptimizationSolver.QuantumOptimizer DEFAULT_OPTIMIZER = + QuantumOptimizer.DECOMPOSE_MULTI_CX; + + private final String scriptPath; + private final String venv; + private final ApplicationContext context; + + @Autowired + public OptimizationSolver( + @Value("${path.circuitprocessing.circuitoptimization}") String scriptPath, + @Value("${venv.circuitprocessing.circuitoptimization}") String venv, + ApplicationContext context + ) { + this.scriptPath = scriptPath; + this.venv = venv; + this.context = context; + } + + @Override + public String getName() { + return "Apply Tket Optimization Pass"; + } + + @Override + public String getDescription() { + return "Transform the given circuit into an optimized but equivalent circuit using" + + "Tket compilation passes (e.g. removing redundancies)."; + } + + @Override + public List> getSubRoutines() { + return List.of(CircuitProcessingSolver.CIRCUIT_PROCESSING_SUBROUTINE); + } + + @Override + public List getSolverSettings() { + return List.of( + new SelectSetting<>( + SETTING_SELECT_OPTIMIZER, + "The optimization pass to refactor the code with", + List.of(OptimizationSolver.QuantumOptimizer.values()), + QuantumOptimizer.DECOMPOSE_MULTI_CX, + OptimizationSolver.QuantumOptimizer::getValue + ) + ); + } + + @Override + public Mono> solve( + String input, + SubRoutineResolver subRoutineResolver, + SolvingProperties properties + ) { + var solution = new Solution<>(this); + + OptimizationSolver.QuantumOptimizer selectedOptimizer = properties + .>getSetting(SETTING_SELECT_OPTIMIZER) + .map(s -> s.getSelectedOptionT(OptimizationSolver.QuantumOptimizer::fromValue)) + .orElse(DEFAULT_OPTIMIZER); + + //String[] inputArray = new String[]{input}; + var processResult = context + .getBean(PythonProcessRunner.class, scriptPath + selectedOptimizer.getScriptPath(), venv) + .withArguments( + ProcessRunner.INPUT_FILE_PATH + ) + .writeInputFile(input) + .readOutputString() + .run(getProblemType(), solution.getId()); + + if (processResult.success() && processResult.output().isPresent()) { + solution.complete(); + solution.setSolutionData(processResult.output().get()); + return subRoutineResolver + .runSubRoutine(CircuitProcessingSolver.CIRCUIT_PROCESSING_SUBROUTINE, + processResult.output().get()); + } + solution.fail(); + processResult.errorOutput().ifPresent(solution::setDebugData); + return Mono.just(solution); + } + + @Override + public ProblemType getProblemType() { + return OptimizationConfiguration.OPTIMIZATION_CONFIG; + } + + enum QuantumOptimizer { + DECOMPOSE_MULTI_CX("DecomposeMultiQubitsCX", + "decompose-multi-cx/decompose_multi_cx_optimizer.py"), + REMOVE_REDUNDANCIES("RemoveRedundancies", + "remove-redundancies/remove_redundancies_optimizer.py"); + + private final String value; + private final String scriptPath; + + QuantumOptimizer(String value, String scriptPath) { + this.value = value; + this.scriptPath = scriptPath; + } + + public String getValue() { + return value; + } + + public String getScriptPath() { + return scriptPath; + } + + public static OptimizationSolver.QuantumOptimizer fromValue(String value) { + for (OptimizationSolver.QuantumOptimizer simulator : values()) { + if (simulator.value.equals(value)) { + return simulator; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 01cdfc62..9fb3dbe3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1 @@ -# default spring profile, correct one will be set during runtime (see ToolboxServerApplication.java) # options: mac, windows, linux spring.profiles.active=linux springdoc.swagger-ui.operationsSorter=alpha springdoc.swagger-ui.tagsSorter=alpha working.directory=jobs examples.directory=examples springdoc.swagger-ui.path=/ # Solvers name.solvers=solvers # Non OS-specific solvers: (typically GAMS and Python) name.gams=gams path.gams=${name.solvers}/${name.gams} name.gams.max-cut=max-cut path.gams.max-cut=${path.gams}/${name.gams.max-cut}/maxcut.gms name.gams.sat=sat path.gams.sat=${path.gams}/${name.gams.sat}/sat.gms name.qiskit=qiskit path.qiskit=${name.solvers}/${name.qiskit} name.qiskit.knapsack=knapsack path.qiskit.knapsack=${path.qiskit}/${name.qiskit.knapsack}/knapsack_qiskit.py venv.qiskit.knapsack=${name.solvers}_${name.qiskit}_${name.qiskit.knapsack} name.qiskit.materialsimulation=materialsimulation path.qiskit.materialsimulation=${path.qiskit}/${name.qiskit.materialsimulation}/material_simulation_qiskit.py venv.qiskit.materialsimulation=${name.solvers}_${name.qiskit}_${name.qiskit.materialsimulation} name.qiskit.max-cut=max-cut path.qiskit.max-cut=${path.qiskit}/${name.qiskit.max-cut}/maxCut_qiskit.py venv.qiskit.max-cut=${name.solvers}_${name.qiskit}_${name.qiskit.max-cut} name.qiskit.qubo=qubo path.qiskit.qubo=${path.qiskit}/${name.qiskit.qubo}/qubo_qiskit.py venv.qiskit.qubo=${name.solvers}_${name.qiskit}_${name.qiskit.qubo} name.cirq=cirq path.cirq=${name.solvers}/${name.cirq} name.cirq.max-cut=max-cut path.cirq.max-cut=${path.cirq}/${name.cirq.max-cut}/max_cut_cirq.py venv.cirq.max-cut=${name.solvers}_${name.cirq}_${name.cirq.max-cut} name.qrisp=qrisp path.qrisp=${name.solvers}/${name.qrisp} name.qrisp.vrp=vrp path.qrisp.vrp=${path.qrisp}/${name.qrisp.vrp}/grover.py venv.qrisp.vrp=${name.solvers}_${name.qrisp}_${name.qrisp.vrp} name.qrisp.qubo=qubo path.qrisp.qubo=${path.qrisp}/${name.qrisp.qubo}/qaoa.py venv.qrisp.qubo=${name.solvers}_${name.qrisp}_${name.qrisp.qubo} name.qrisp.sat=sat path.qrisp.sat.grover=${path.qrisp}/${name.qrisp.sat}/grover.py path.qrisp.sat.exact=${path.qrisp}/${name.qrisp.sat}/exact_grover.py venv.qrisp.sat=${name.solvers}_${name.qrisp}_${name.qrisp.sat} name.dwave=dwave path.dwave=${name.solvers}/${name.dwave} name.dwave.qubo=qubo path.dwave.qubo=${path.dwave}/${name.dwave.qubo}/main.py venv.dwave.qubo=${name.solvers}_${name.dwave}_${name.dwave.qubo} # Non OS-specific custom solvers: (solvers that are not part of a framework) name.custom=custom path.custom=${name.solvers}/${name.custom} name.custom.hs-knapsack=hs-knapsack path.custom.hs-knapsack=${path.custom}/${name.custom.hs-knapsack}/knapsack.py venv.custom.hs-knapsack=${name.solvers}_${name.custom}_${name.custom.hs-knapsack} name.custom.lkh=lkh path.custom.lkh=${path.custom}/${name.custom.lkh}/vrp_lkh.py venv.custom.lkh=${name.solvers}_${name.custom}_${name.custom.lkh} name.custom.berger-vrp=berger-vrp name.custom.sharp-sat-bruteforce=sharp-sat-bruteforce path.custom.sharp-sat-bruteforce=${path.custom}/${name.custom.sharp-sat-bruteforce}/exact-solution-counter.py venv.custom.sharp-sat-bruteforce=${name.solvers}_${name.custom}_${name.custom.sharp-sat-bruteforce} name.custom.sharp-sat-ganak=sharp-sat-ganak venv.custom.sharp-sat-ganak=${name.solvers}_${name.custom}_${name.custom.sharp-sat-ganak} # Demonstrators name.demonstrators=demonstrators name.demonstrators.cplex=cplex path.demonstrators.cplex=${name.demonstrators}/${name.demonstrators.cplex} name.demonstrators.cplex.mip=mip-solver path.demonstrators.cplex.mip=${path.demonstrators.cplex}/${name.demonstrators.cplex.mip}/mip-solver.py venv.demonstrators.cplex.mip=${name.demonstrators}_${name.demonstrators.cplex}_${name.demonstrators.cplex.mip} name.demonstrators.qiskit=qiskit path.demonstrators.qiskit=${name.demonstrators}/${name.demonstrators.qiskit} name.demonstrators.qiskit.molecule-energy=molecule-energy path.demonstrators.qiskit.molecule-energy=${path.demonstrators.qiskit}/${name.demonstrators.qiskit.molecule-energy}/molecule-energy.py venv.demonstrators.qiskit.molecule-energy=${name.demonstrators}_${name.demonstrators.qiskit}_${name.demonstrators.qiskit.molecule-energy} \ No newline at end of file +# default spring profile, correct one will be set during runtime (see ToolboxServerApplication.java) # options: mac, windows, linux spring.profiles.active=linux springdoc.swagger-ui.operationsSorter=alpha springdoc.swagger-ui.tagsSorter=alpha working.directory=jobs examples.directory=examples springdoc.swagger-ui.path=/ # Solvers name.solvers=solvers # Non OS-specific solvers: (typically GAMS and Python) name.gams=gams path.gams=${name.solvers}/${name.gams} name.gams.max-cut=max-cut path.gams.max-cut=${path.gams}/${name.gams.max-cut}/maxcut.gms name.gams.sat=sat path.gams.sat=${path.gams}/${name.gams.sat}/sat.gms name.qiskit=qiskit path.qiskit=${name.solvers}/${name.qiskit} name.qiskit.knapsack=knapsack path.qiskit.knapsack=${path.qiskit}/${name.qiskit.knapsack}/knapsack_qiskit.py venv.qiskit.knapsack=${name.solvers}_${name.qiskit}_${name.qiskit.knapsack} name.qiskit.materialsimulation=materialsimulation path.qiskit.materialsimulation=${path.qiskit}/${name.qiskit.materialsimulation}/material_simulation_qiskit.py venv.qiskit.materialsimulation=${name.solvers}_${name.qiskit}_${name.qiskit.materialsimulation} name.qiskit.max-cut=max-cut path.qiskit.max-cut=${path.qiskit}/${name.qiskit.max-cut}/maxCut_qiskit.py venv.qiskit.max-cut=${name.solvers}_${name.qiskit}_${name.qiskit.max-cut} name.qiskit.qubo=qubo path.qiskit.qubo=${path.qiskit}/${name.qiskit.qubo}/qubo_qiskit.py venv.qiskit.qubo=${name.solvers}_${name.qiskit}_${name.qiskit.qubo} name.cirq=cirq path.cirq=${name.solvers}/${name.cirq} name.cirq.max-cut=max-cut path.cirq.max-cut=${path.cirq}/${name.cirq.max-cut}/max_cut_cirq.py venv.cirq.max-cut=${name.solvers}_${name.cirq}_${name.cirq.max-cut} name.qrisp=qrisp path.qrisp=${name.solvers}/${name.qrisp} name.qrisp.vrp=vrp path.qrisp.vrp=${path.qrisp}/${name.qrisp.vrp}/grover.py venv.qrisp.vrp=${name.solvers}_${name.qrisp}_${name.qrisp.vrp} name.qrisp.qubo=qubo path.qrisp.qubo=${path.qrisp}/${name.qrisp.qubo}/qaoa.py venv.qrisp.qubo=${name.solvers}_${name.qrisp}_${name.qrisp.qubo} name.qrisp.sat=sat path.qrisp.sat.grover=${path.qrisp}/${name.qrisp.sat}/grover.py path.qrisp.sat.exact=${path.qrisp}/${name.qrisp.sat}/exact_grover.py venv.qrisp.sat=${name.solvers}_${name.qrisp}_${name.qrisp.sat} name.dwave=dwave path.dwave=${name.solvers}/${name.dwave} name.dwave.qubo=qubo path.dwave.qubo=${path.dwave}/${name.dwave.qubo}/main.py venv.dwave.qubo=${name.solvers}_${name.dwave}_${name.dwave.qubo} # Non OS-specific custom solvers: (solvers that are not part of a framework) name.custom=custom path.custom=${name.solvers}/${name.custom} name.custom.hs-knapsack=hs-knapsack path.custom.hs-knapsack=${path.custom}/${name.custom.hs-knapsack}/knapsack.py venv.custom.hs-knapsack=${name.solvers}_${name.custom}_${name.custom.hs-knapsack} name.custom.lkh=lkh path.custom.lkh=${path.custom}/${name.custom.lkh}/vrp_lkh.py venv.custom.lkh=${name.solvers}_${name.custom}_${name.custom.lkh} name.custom.berger-vrp=berger-vrp name.custom.sharp-sat-bruteforce=sharp-sat-bruteforce path.custom.sharp-sat-bruteforce=${path.custom}/${name.custom.sharp-sat-bruteforce}/exact-solution-counter.py venv.custom.sharp-sat-bruteforce=${name.solvers}_${name.custom}_${name.custom.sharp-sat-bruteforce} name.custom.sharp-sat-ganak=sharp-sat-ganak venv.custom.sharp-sat-ganak=${name.solvers}_${name.custom}_${name.custom.sharp-sat-ganak} # Demonstrators name.demonstrators=demonstrators name.demonstrators.cplex=cplex path.demonstrators.cplex=${name.demonstrators}/${name.demonstrators.cplex} name.demonstrators.cplex.mip=mip-solver path.demonstrators.cplex.mip=${path.demonstrators.cplex}/${name.demonstrators.cplex.mip}/mip-solver.py venv.demonstrators.cplex.mip=${name.demonstrators}_${name.demonstrators.cplex}_${name.demonstrators.cplex.mip} name.demonstrators.qiskit=qiskit path.demonstrators.qiskit=${name.demonstrators}/${name.demonstrators.qiskit} name.demonstrators.qiskit.molecule-energy=molecule-energy path.demonstrators.qiskit.molecule-energy=${path.demonstrators.qiskit}/${name.demonstrators.qiskit.molecule-energy}/molecule-energy.py venv.demonstrators.qiskit.molecule-energy=${name.demonstrators}_${name.demonstrators.qiskit}_${name.demonstrators.qiskit.molecule-energy} name.circuitprocessing=circuitprocessing path.circuitprocessing=${name.solvers}/${name.circuitprocessing} name.circuitprocessing.circuitexecution=circuitexecution path.circuitprocessing.circuitexecution=${path.circuitprocessing}/${name.circuitprocessing.circuitexecution}/ venv.circuitprocessing.circuitexecution=${name.solvers}_${name.circuitprocessing}_${name.circuitprocessing.circuitexecution} name.circuitprocessing.circuitoptimization=circuitoptimizing path.circuitprocessing.circuitoptimization=${path.circuitprocessing}/${name.circuitprocessing.circuitoptimization}/ venv.circuitprocessing.circuitoptimization=${name.solvers}_${name.circuitprocessing}_${name.circuitprocessing.circuitoptimization} \ No newline at end of file diff --git a/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/bell-state.qasm b/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/bell-state.qasm new file mode 100644 index 00000000..c3bf3c2b --- /dev/null +++ b/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/bell-state.qasm @@ -0,0 +1,8 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[2]; +creg c[2]; +h q[0]; +cx q[0],q[1]; +measure q[0] -> c[0]; +measure q[1] -> c[1]; diff --git a/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/cswap.qasm b/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/cswap.qasm new file mode 100644 index 00000000..b2bce4dc --- /dev/null +++ b/src/main/resources/edu/kit/provideq/toolbox/circuit/processing/cswap.qasm @@ -0,0 +1,6 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[3]; +crz(0.5) q[0], q[1]; +t q[2]; +cswap q[2], q[0], q[1]; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/CircuitProcessingSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/CircuitProcessingSolversTest.java new file mode 100644 index 00000000..e31e8382 --- /dev/null +++ b/src/test/java/edu/kit/provideq/toolbox/api/CircuitProcessingSolversTest.java @@ -0,0 +1,112 @@ +package edu.kit.provideq.toolbox.api; + +import static edu.kit.provideq.toolbox.circuit.processing.CircuitProcessingConfiguration.CIRCUIT_PROCESSING; +import static edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutorConfiguration.EXECUTOR_CONFIG; +import static edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationConfiguration.MITIGATION_CONFIG; +import static edu.kit.provideq.toolbox.circuit.processing.solver.optimization.OptimizationConfiguration.OPTIMIZATION_CONFIG; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToExecutionSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToMitigationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToOptimizationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutionSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.optimization.OptimizationSolver; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemManagerProvider; +import java.time.Duration; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest +@AutoConfigureMockMvc +class CircuitProcessingSolversTest { + @Autowired + private WebTestClient client; + + @Autowired + private ProblemManagerProvider problemManagerProvider; + + @Autowired + private MoveToMitigationSolver moveToMitigationSolver; + + @Autowired + private MoveToExecutionSolver moveToExecutionSolver; + + @Autowired + private MoveToOptimizationSolver moveToOptimizationSolver; + + @Autowired + private ErrorMitigationSolver errorMitigationSolver; + + @Autowired + private ExecutionSolver executionSolver; + + @Autowired + private OptimizationSolver optimizationSolver; + + private ProblemManager problemManager; + private List problems; + + @BeforeEach + void beforeEach() { + this.client = this.client.mutate() + .responseTimeout(Duration.ofSeconds(60)) + .build(); + problemManager = problemManagerProvider.findProblemManagerForType(CIRCUIT_PROCESSING).get(); + problems = problemManager.getExampleInstances() + .stream() + .map(Problem::getInput) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + @Test + void testMoveToMitigationSolver() { + var circuit = problems.get(0); + var problemDto = ApiTestHelper.createProblem(client, moveToMitigationSolver, circuit, CIRCUIT_PROCESSING); + var subProblemId = problemDto.getSubProblems().get(0).getSubProblemIds().get(0); + ApiTestHelper.setProblemSolver(client, errorMitigationSolver, subProblemId, MITIGATION_CONFIG.getId()); + var solvedDto = ApiTestHelper.trySolveFor(60, client, problemDto.getId(), CIRCUIT_PROCESSING); + ApiTestHelper.testSolution(solvedDto); + assertEquals(circuit, solvedDto.getSolution().getSolutionData()); + } + + @Test + void testMoveToExecutionSolver() { + var circuit = problems.get(0); + var problemDto = ApiTestHelper.createProblem(client, moveToExecutionSolver, circuit, CIRCUIT_PROCESSING); + var subProblemId = problemDto.getSubProblems().get(0).getSubProblemIds().get(0); + ApiTestHelper.setProblemSolver(client, executionSolver, subProblemId, EXECUTOR_CONFIG.getId()); + var solvedDto = ApiTestHelper.trySolveFor(60, client, problemDto.getId(), CIRCUIT_PROCESSING); + ApiTestHelper.testSolution(solvedDto); + assertFalse(solvedDto.getSolution().getSolutionData().isBlank()); + } + + @Test + void testMoveToOptimizationSolver() { + var circuit = problems.get(0); + var problemDto = ApiTestHelper.createProblem(client, moveToOptimizationSolver, circuit, CIRCUIT_PROCESSING); + var optSubProblemId = problemDto.getSubProblems().get(0).getSubProblemIds().get(0); + var optDto = ApiTestHelper.setProblemSolver( + client, optimizationSolver, optSubProblemId, OPTIMIZATION_CONFIG.getId()); + var circuitSubProblemId = optDto.getSubProblems().get(0).getSubProblemIds().get(0); + var mitigationEntryDto = ApiTestHelper.setProblemSolver( + client, moveToMitigationSolver, circuitSubProblemId, CIRCUIT_PROCESSING.getId()); + var mitigationId = mitigationEntryDto.getSubProblems().get(0).getSubProblemIds().get(0); + ApiTestHelper.setProblemSolver(client, errorMitigationSolver, mitigationId, MITIGATION_CONFIG.getId()); + var solvedDto = ApiTestHelper.trySolveFor(120, client, problemDto.getId(), CIRCUIT_PROCESSING); + ApiTestHelper.testSolution(solvedDto); + assertTrue(solvedDto.getSolution().getSolutionData().contains("OPENQASM")); + } +} diff --git a/src/test/java/edu/kit/provideq/toolbox/api/ErrorMitigationSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/ErrorMitigationSolverTest.java new file mode 100644 index 00000000..1815a325 --- /dev/null +++ b/src/test/java/edu/kit/provideq/toolbox/api/ErrorMitigationSolverTest.java @@ -0,0 +1,52 @@ +package edu.kit.provideq.toolbox.api; + +import static edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationConfiguration.MITIGATION_CONFIG; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationSolver; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemManagerProvider; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest +@AutoConfigureMockMvc +class ErrorMitigationSolverTest { + @Autowired + private WebTestClient client; + + @Autowired + private ProblemManagerProvider problemManagerProvider; + + @Autowired + private ErrorMitigationSolver errorMitigationSolver; + + private ProblemManager problemManager; + private List problems; + + @BeforeEach + void beforeEach() { + problemManager = problemManagerProvider.findProblemManagerForType(MITIGATION_CONFIG).get(); + problems = problemManager.getExampleInstances() + .stream() + .map(Problem::getInput) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + @Test + void testErrorMitigationSolver() { + var circuit = problems.get(0); + var problem = ApiTestHelper.createProblem(client, errorMitigationSolver, circuit, MITIGATION_CONFIG); + ApiTestHelper.testSolution(problem); + assertEquals(circuit, problem.getSolution().getSolutionData()); + } +} diff --git a/src/test/java/edu/kit/provideq/toolbox/api/ExecutionSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/ExecutionSolverTest.java new file mode 100644 index 00000000..11549377 --- /dev/null +++ b/src/test/java/edu/kit/provideq/toolbox/api/ExecutionSolverTest.java @@ -0,0 +1,56 @@ +package edu.kit.provideq.toolbox.api; + +import static edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutorConfiguration.EXECUTOR_CONFIG; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.circuit.processing.solver.executor.ExecutionSolver; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManagerProvider; +import java.time.Duration; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest +@AutoConfigureMockMvc +class ExecutionSolverTest { + @Autowired + private WebTestClient client; + + @Autowired + private ProblemManagerProvider problemManagerProvider; + + @Autowired + private ExecutionSolver executionSolver; + + private List problems; + + @BeforeEach + void beforeEach() { + this.client = this.client.mutate() + .responseTimeout(Duration.ofSeconds(60)) + .build(); + problems = problemManagerProvider.findProblemManagerForType(EXECUTOR_CONFIG).get() + .getExampleInstances() + .stream() + .map(Problem::getInput) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + @Test + void testExecutionSolver() { + var circuit = problems.get(0); + var problem = ApiTestHelper.createProblem(client, executionSolver, circuit, EXECUTOR_CONFIG); + ApiTestHelper.testSolution(problem); + Solution solution = problem.getSolution(); + assertTrue(solution.getSolutionData().toString().contains("OPENQASM")); + } +} diff --git a/src/test/java/edu/kit/provideq/toolbox/api/OptimizationSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/OptimizationSolverTest.java new file mode 100644 index 00000000..4945a5c7 --- /dev/null +++ b/src/test/java/edu/kit/provideq/toolbox/api/OptimizationSolverTest.java @@ -0,0 +1,72 @@ +package edu.kit.provideq.toolbox.api; + +import static edu.kit.provideq.toolbox.circuit.processing.CircuitProcessingConfiguration.CIRCUIT_PROCESSING; +import static edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationConfiguration.MITIGATION_CONFIG; +import static edu.kit.provideq.toolbox.circuit.processing.solver.optimization.OptimizationConfiguration.OPTIMIZATION_CONFIG; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import edu.kit.provideq.toolbox.circuit.processing.solver.MoveToMitigationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.mitigation.ErrorMitigationSolver; +import edu.kit.provideq.toolbox.circuit.processing.solver.optimization.OptimizationSolver; +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemManagerProvider; +import java.time.Duration; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest +@AutoConfigureMockMvc +class OptimizationSolverTest { + @Autowired + private WebTestClient client; + + @Autowired + private ProblemManagerProvider problemManagerProvider; + + @Autowired + private OptimizationSolver optimizationSolver; + + @Autowired + private MoveToMitigationSolver moveToMitigationSolver; + + @Autowired + private ErrorMitigationSolver errorMitigationSolver; + + private ProblemManager problemManager; + private List problems; + + @BeforeEach + void beforeEach() { + this.client = this.client.mutate() + .responseTimeout(Duration.ofSeconds(60)) + .build(); + problemManager = problemManagerProvider.findProblemManagerForType(OPTIMIZATION_CONFIG).get(); + problems = problemManager.getExampleInstances() + .stream() + .map(Problem::getInput) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + @Test + void testOptimizationSolver() { + var circuit = problems.get(0); + var problemDto = ApiTestHelper.createProblem(client, optimizationSolver, circuit, OPTIMIZATION_CONFIG); + var circuitSubProblemId = problemDto.getSubProblems().get(0).getSubProblemIds().get(0); + var mitigationEntryDto = ApiTestHelper.setProblemSolver( + client, moveToMitigationSolver, circuitSubProblemId, CIRCUIT_PROCESSING.getId()); + var mitigationId = mitigationEntryDto.getSubProblems().get(0).getSubProblemIds().get(0); + ApiTestHelper.setProblemSolver(client, errorMitigationSolver, mitigationId, MITIGATION_CONFIG.getId()); + var solvedDto = ApiTestHelper.trySolveFor(120, client, problemDto.getId(), OPTIMIZATION_CONFIG); + ApiTestHelper.testSolution(solvedDto); + assertTrue(solvedDto.getSolution().getSolutionData().contains("OPENQASM")); + } +}