Skip to content

Commit

Permalink
feature/new-execution-script (#37)
Browse files Browse the repository at this point in the history
* initial version of framework exectution

* updated classiq to 0.37

* reorganized execution script to improve readability
  • Loading branch information
dmark04 authored Feb 14, 2024
1 parent f6b5f2a commit ffc3cde
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 101 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ flowchart TD
D{"QLS.solve()"} --> CH{{check}}
CH --> S{{"impl.solve()"}}
end
A(Matrix A, vector x) -->|inside| B[Class ToyModel]
A(Matrix A, vector b) -->|inside| B[Class ToyModel]
M(Implementations HHL/VQLS, Classiq/qiskit) ---> |method| D
B --> |A,x| D
B --> |A,b| D
S --> Q(QASM circuit)
S --> V(StateVector)
S --> V("StateVector |x>")
```
184 changes: 94 additions & 90 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ include = ["CHANGELOG.md"]

[tool.poetry.dependencies]
python = ">=3.9, <3.12" # >=3.9 because of amazon-braket, <3.12 because of classiq
classiq = "^0.36"
classiq = "^0.37.0"
qiskit = "^0.46.0"
qiskit-algorithms = "^0.2.1"
matplotlib = "^3.8.2" # this version could be lowered to 3.5.0 or even further back
Expand Down
93 changes: 93 additions & 0 deletions quantum_linear_systems/execute_framework.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import argparse

import numpy as np
import yaml # type: ignore[import-untyped]

from quantum_linear_systems.quantum_linear_solver import QuantumLinearSolver
from quantum_linear_systems.toymodels import ClassiqDemoExample


def parse_arguments() -> argparse.Namespace:
arg_parser = argparse.ArgumentParser(description="Quantum Linear Systems Framework")
arg_parser.add_argument(
"-m",
"--matrix_csv",
help="CSV file containing the matrix A.",
required=False,
type=str,
)
arg_parser.add_argument(
"-v",
"--vector_csv",
help="CSV file containing the vector b.",
required=False,
type=str,
)
arg_parser.add_argument(
"-i",
"--implementation",
help="Implementation to solve the problem Ax=b.",
required=True,
type=str,
)
arg_parser.add_argument(
"-iargs",
"--implementation_args",
type=str,
help="Path to a YAML file containing a specific parameters to be passed to the implementation.",
required=False,
)

args = arg_parser.parse_args()

if args.matrix_csv:
args.matrix_a = np.loadtxt(args.matrix_csv, delimiter=",")
else:
print("No matrix provided. Falling back to ToyModel.")
toymodel = ClassiqDemoExample()
args.matrix_a = toymodel.matrix_a
if args.vector_csv:
args.vector_b = np.loadtxt(args.vector_csv, delimiter=",")
else:
print("No vector provided. Falling back to ToyModel.")
toymodel = ClassiqDemoExample()
args.vector_b = toymodel.vector_b
if args.implementation not in ["hhl_qiskit", "vqls_qiksit", "hhl_classiq"]:
raise ValueError(f"Unknown implementation {args.implementation}.")
if args.implementation_args:
with open(args.implementation_args, "r") as file:
try:
args.implementation_args = yaml.safe_load(file)
except yaml.YAMLError as e:
raise ValueError(f"Error loading YAML argument file: {e}")
else:
args.implementation_args = {}

return args


if __name__ == "__main__":
parsed_args = parse_arguments()

qls = QuantumLinearSolver()

# perform checks (add more meaningful checks here, also implementation specific checks)
qls.check_matrix_square_hermitian(parsed_args.matrix_a)

# solve
qls.solve(
matrix_a=parsed_args.matrix_a,
vector_b=parsed_args.vector_b,
method=parsed_args.implementation,
file_basename="default_run",
**parsed_args.implementation_args,
)

# todo: backend execution
# this is currently still hardcoded into the implementations (with the exception of `hhl_qiskit`)
# we do have access to the qasm circuits through `qls.qasm_circuit`.
# However, especially with hybrid algorithms such as VQLS, we need to think about how to actually execute them on different backends

print(
f"Solution: {qls.solution}\nCircuit depth: {qls.circuit_depth}\nCircuit width: {qls.circuit_width}\nRuntime: {qls.run_time}"
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
from linear_solvers import HHL
from linear_solvers import LinearSolverResult
from qiskit.providers import Backend
from qiskit.quantum_info import Statevector

from quantum_linear_systems.plotting import print_results
Expand All @@ -16,7 +17,10 @@


def solve_hhl_qiskit(
matrix_a: np.ndarray, vector_b: np.ndarray, show_circuit: bool = False
matrix_a: np.ndarray,
vector_b: np.ndarray,
show_circuit: bool = False,
backend: Backend = None,
) -> Tuple[np.ndarray, str, int, int, float]:
"""Solve linear system Ax=b using HHL implemented in qiskit based on the quantum
linear solvers package.
Expand All @@ -27,7 +31,7 @@ def solve_hhl_qiskit(
start_time = time.time()

# solve HHL using qiskit
hhl_implementation = HHL()
hhl_implementation = HHL(quantum_instance=backend)
naive_hhl_solution: LinearSolverResult = hhl_implementation.solve(
matrix=matrix_a, vector=vector_b
)
Expand Down
11 changes: 6 additions & 5 deletions quantum_linear_systems/quantum_linear_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ def __init__(self) -> None:
self.circuit_depth: int
self.run_time: float

def check_matrix_square_hermitian(self) -> None:
@staticmethod
def check_matrix_square_hermitian(matrix_a: np.ndarray) -> None:
"""Check if the coefficient matrix A is square and Hermitian."""
if self.matrix_a.shape[0] != self.matrix_a.shape[1]:
if matrix_a.shape[0] != matrix_a.shape[1]:
raise ValueError(
f"Input matrix A needs to be square, not "
f"{self.matrix_a.shape[0]}x{self.matrix_a.shape[1]}."
f"{matrix_a.shape[0]}x{matrix_a.shape[1]}."
)
if not np.allclose(self.matrix_a, np.conj(self.matrix_a.T)):
if not np.allclose(matrix_a, np.conj(matrix_a.T)):
raise ValueError("Input matrix A is not hermitian!")

def circuit_data(self) -> Tuple[str, int, int]:
Expand Down Expand Up @@ -83,7 +84,7 @@ def solve(
method,
)
# currently all implemented solvers share these requirements
self.check_matrix_square_hermitian()
self.check_matrix_square_hermitian(self.matrix_a)

# self.normalize_model() # this should be in the respective solver method if it is needed

Expand Down

0 comments on commit ffc3cde

Please sign in to comment.