Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bin/test

### IntelliJ IDEA ###
.idea
.junie
*.iws
*.iml
*.ipr
Expand Down
52 changes: 52 additions & 0 deletions config/checkstyle/intellij_codestyle.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<code_scheme name="Default copy" version="173">
<JavaCodeStyleSettings>
<option name="SPACE_INSIDE_ONE_LINE_ENUM_BRACES" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
</JavaCodeStyleSettings>
<codeStyleSettings language="Cookie">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="false" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="100" />
<option name="BLANK_LINES_BEFORE_PACKAGE" value="1" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="ASSERT_STATEMENT_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="1" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
40 changes: 40 additions & 0 deletions solvers/circuitprocessing/circuitexecution/executor.py
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 3 additions & 0 deletions solvers/circuitprocessing/circuitexecution/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytket
pytket-qiskit
# pytket-qulacs
Original file line number Diff line number Diff line change
@@ -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))

Original file line number Diff line number Diff line change
@@ -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))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytket
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from qiskit import QuantumCircuit
from qiskit.circuit import Gate
from qiskit.circuit.library import QFT
from math import pi
from typing import Optional

def constant_qft_add_gate(n_bits: int, const: int, name: Optional[str] = None) -> Gate:
"""
QFT-based constant adder: |v> -> |(v + const) mod 2^n_bits>.
Uses QFT, per-qubit phase rotations, and inverse QFT.
"""

qc = QuantumCircuit(n_bits, name=name or f"AddConst({const})")
qft_gate = QFT(n_bits, do_swaps=False).to_gate(label="QFT")
iqft_gate = qft_gate.inverse()

qc.append(qft_gate, range(n_bits))
for k in range(n_bits):
angle = 2 * pi * const / (2 ** (k + 1))
qc.p(angle, k)
qc.append(iqft_gate, range(n_bits))
return qc.to_gate(label=name or f"AddConst({const})")



def constant_qft_sub_gate(n_bits: int, const: int, name: Optional[str] = None) -> Gate:
"""
QFT-based constant subtractor: |v> -> |(v - const) mod 2^n_bits>.
Implemented by flipping the signs of the adder’s phase rotations [1].
"""
return constant_qft_add_gate(n_bits, const=-const, name=name or f"SubConst({const})")

Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
from typing import Dict, List, Sequence, Any, Union, Optional
from qiskit import QuantumCircuit, QuantumRegister, AncillaRegister
from qiskit.circuit import Instruction, ClassicalRegister
from knapsack.knapsack import KnapsackInstance



class RegisterBank:
"""
Helper to keep named registers organized.
"""

def __init__(self):
self.q: Dict[str, QuantumRegister] = {}
self.c: Dict[str, ClassicalRegister] = {}
self.a: Dict[str, AncillaRegister] = {}

def add_qubits(self, name: str, size: int) -> QuantumRegister:
if name in self.q:
raise ValueError(f"Quantum register '{name}' already exists")
reg = QuantumRegister(size, name=name)
self.q[name] = reg
return reg

def add_ancilla(self, name: str, size: int) -> AncillaRegister:
if name in self.a:
raise ValueError(f"Ancilla register '{name}' already exists")
reg = AncillaRegister(size, name=name)
self.a[name] = reg
return reg

def add_clbits(self, name: str, size: int) -> ClassicalRegister:
if name in self.c:
raise ValueError(f"Classical register '{name}' already exists")
reg = ClassicalRegister(size, name=name)
self.c[name] = reg
return reg

def get(self, name: List[str]) -> Union[QuantumRegister, AncillaRegister, ClassicalRegister]:
list_of_registers = []
for n in name:
if n in self.q:
list_of_registers.append(self.q[n])
if n in self.a:
list_of_registers.append(self.a[n])
if n in self.c:
list_of_registers.append(self.c[n])
if len(list_of_registers) == 1:
return list_of_registers[0]
elif len(list_of_registers) > 1:
return list_of_registers
else:
raise KeyError(f"Register '{name}' not found")

def has_measurements(self) -> bool:
return len(self.c) > 0


class Circuit:
"""
Thin wrapper around QuantumCircuit with named register management.
"""

def __init__(self, name: str = "circuit"):
self.name = name
self.registers = RegisterBank()
self.qc = QuantumCircuit(name=name)
self.metadata: Dict[str, Any] = {}

def add_qubits(self, name: str, size: int) -> QuantumRegister:
reg = self.registers.add_qubits(name, size)
self.qc.add_register(reg)
return reg

def add_ancilla(self, name: str, size: int) -> AncillaRegister:
reg = self.registers.add_ancilla(name, size)
self.qc.add_register(reg)
return reg

def add_clbits(self, name: str, size: int) -> ClassicalRegister:
reg = self.registers.add_clbits(name, size)
self.qc.add_register(reg)
return reg

def get_register(self, name: Union[str, List[str]]) -> Union[QuantumRegister, AncillaRegister, ClassicalRegister]:
"""Get a register by name."""
if isinstance(name, str):
return self.registers.get([name])
return self.registers.get(name)

def get_qubits_in_registers(self, names: List[str] = [], all=False) -> List[Any]:
"""Get all qubits in the specified registers as a flat list."""
if all and len(names) != 0:
raise ValueError("If 'all' is True, 'names' must be an empty list.")
if not all and len(names) == 0:
raise ValueError("If 'all' is False, 'names' must contain at least one register name.")

if all:
names = list(self.registers.q.keys()) + list(self.registers.a.keys()) + list(self.registers.c.keys())
qubits = []
for name in names:
reg = self.get_register(name)
for q in reg:
qubits.append(q)
return qubits


def append_instruction(
self,
inst: Instruction,
qargs: Sequence[Any],
cargs: Optional[Sequence[Any]] = None,
):
self.qc.append(inst, qargs, [] if cargs is None else cargs)

def append_subcircuit_as_instruction(
self,
sub: QuantumCircuit,
qubits: Sequence[Any],
clbits: Optional[Sequence[Any]] = None,
name: Optional[str] = None,
):
"""Append a subcircuit as a single instruction to this circuit."""
inst = sub.to_instruction()
if name:
inst.name = name
self.append_instruction(inst, qubits, [] if clbits is None else clbits)



def append_subcircuit_inline_simple(self, sub: QuantumCircuit):
"""
Adding instruction 1 by 1 without mapping, assuming:
- both circuits have the same number of qubits,
- no classical bits are present.
"""
if len(sub.qc.clbits) != 0 or len(self.qc.clbits) != 0:
raise ValueError("This simplified method requires circuits without classical bits.")
if len(sub.qc.qubits) != len(self.qc.qubits):
raise ValueError("Both circuits must have the same number of qubits.")

# Map sub qubits -> target qubits by index
qmap = {sub_q: self.qc.qubits[i] for i, sub_q in enumerate(sub.qc.qubits)}

# Append each instruction as-is
for ci in sub.qc.data:
op = ci.operation
mapped_qargs = [qmap[q] for q in ci.qubits]
self.qc.append(op, mapped_qargs, [])

def to_instruction(self, name: Optional[str] = None) -> Instruction:
inst = self.qc.to_instruction()
if name:
inst.name = name
return inst

def prepare_knapsack_circuit(self, knapsack_instance: 'KnapsackInstance', has_ancillas = False) -> None:
"""Prepare the quantum circuit for the knapsack problem."""
self.add_qubits("items", knapsack_instance.num_items)
self.add_qubits("capacity", knapsack_instance.capacity.bit_length())
max_profit = sum(it.value for it in knapsack_instance.items)
self.add_qubits("profit", max_profit.bit_length())
self.add_ancilla("oracle", 1)
if has_ancillas:
self.add_ancilla("compare_flag", 1)
self.add_ancilla("comparator", max(knapsack_instance.num_items, knapsack_instance.capacity.bit_length(), max_profit.bit_length()))
# set capacity register to knapsack capacity


def measure_items(self, creg_name: str = "items_c"):
self.add_clbits(creg_name, len(self.get_register("items")))
# Freeze ordering before measuring
self.qc.barrier(*self.qc.qubits)
self.measure_register("items", creg_name)

def measure_register(self, qreg_name: str, creg_name: str):
qreg = self.get_register(qreg_name)
creg = self.get_register(creg_name)
self.qc.measure(qreg, creg)


def draw(self, output: str = "text") -> Any:
return self.qc.draw(output=output)

def get_circuit_as_instruction(self, name: Optional[str] = None) -> Instruction:
inst = self.qc.to_instruction()
if name:
inst.name = name
return inst






Loading
Loading