Skip to content

Commit

Permalink
normalize incoming instructions ot quil-rs types
Browse files Browse the repository at this point in the history
  • Loading branch information
MarquessV committed Jul 24, 2023
1 parent 9461f29 commit 9349b7c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 39 deletions.
79 changes: 43 additions & 36 deletions pyquil/quil.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def instructions(self, instructions: List[AbstractInstruction]):
new_program.inst(instructions)
self._program = new_program._program

def inst(self, *instructions: InstructionDesignator) -> "Program":
def inst(self, *instructions: Union[InstructionDesignator, RSProgram]) -> "Program":
"""
Mutates the Program object by appending new instructions.
Expand Down Expand Up @@ -231,15 +231,15 @@ def inst(self, *instructions: InstructionDesignator) -> "Program":
else:
self.inst(" ".join(map(str, instruction)))
elif isinstance(instruction, str):
self.inst(RSProgram.parse(instruction.strip()))
self.inst(RSProgram.parse(instruction.strip()).instructions)
elif isinstance(instruction, Program):
self.inst(instruction._program)
elif isinstance(instruction, quil_rs.Instruction):
self._program.add_instruction(instruction)
self._add_instruction(instruction)
elif isinstance(instruction, AbstractInstruction):
self._add_instruction(_convert_to_rs_instruction(instruction))
elif isinstance(instruction, RSProgram):
self._program += instruction
elif isinstance(instruction, AbstractInstruction):
self._add_instruction(instruction)
else:
try:
instruction = quil_rs.Instruction(instruction)
Expand All @@ -249,72 +249,79 @@ def inst(self, *instructions: InstructionDesignator) -> "Program":

return self

def _add_instruction(self, instruction: AbstractInstruction):
if isinstance(instruction, DefGate):
def _add_instruction(self, instruction: quil_rs.Instruction):
if instruction.is_gate_definition():
defgate = instruction.to_gate_definition()
# If the gate definition differs from the current one, print a warning and replace it.
idx, existing_defgate = next(
(
(i, gate)
for i, gate in enumerate(self.instructions)
if isinstance(gate, DefGate) and gate.name == instruction.name
for i, gate in enumerate(map(lambda inst: inst.as_gate_definition(), self._program.instructions))
if gate and gate.name == defgate.name
),
(0, None),
)

if existing_defgate is None:
self.inst(RSProgram.parse(instruction.out()))
self._program.add_instruction(instruction)
elif (
instruction.matrix.dtype in [np.float_, np.complex_]
and np.allclose(existing_defgate.matrix, instruction.matrix)
) or not np.all(existing_defgate.matrix == instruction.matrix):
warnings.warn("Redefining gate {}".format(instruction.name))
new_instructions = self.instructions[:idx] + [instruction] + self.instructions[idx + 1 :]
self.instructions = new_instructions
elif isinstance(instruction, DefCalibration):
existing_defgate.specification != defgate.specification
or existing_defgate.specification.inner() != existing_defgate.specification.inner()
):
warnings.warn("Redefining gate {}".format(defgate.name))
new_instructions = (
self._program.instructions[:idx] + [instruction] + self._program.instructions[idx + 1 :]
)
self._program = self._program.clone_without_body_instructions()
self._program.add_instructions(new_instructions)
elif instruction.is_calibration_definition():
defcal = instruction.to_calibration_definition()
idx, existing_calibration = next(
(
(i, calibration)
for i, calibration in enumerate(self.calibrations)
if calibration.name == instruction.name
and calibration.parameters == instruction.parameters
and calibration.qubits == instruction.qubits
(i, existing_calibration)
for i, existing_calibration in enumerate(self._program.calibrations.calibrations)
if defcal.name == existing_calibration.name
and defcal.parameters == existing_calibration.parameters
and defcal.qubits == existing_calibration.qubits
),
(0, None),
)
if existing_calibration is None:
self._program.add_instruction(_convert_to_rs_instruction(instruction))
self._program.add_instruction(instruction)

elif existing_calibration.out() != instruction.out():
warnings.warn("Redefining calibration {}".format(instruction.name))
elif (
existing_calibration.instructions != defcal.instructions
or existing_calibration.modifiers != defcal.modifiers
):
warnings.warn("Redefining calibration {}".format(defcal.name))
current_calibrations = self._program.calibrations
new_calibrations = CalibrationSet(
current_calibrations.calibrations[:idx]
+ [instruction]
+ current_calibrations.calibrations[idx + 1 :],
current_calibrations.calibrations[:idx] + [defcal] + current_calibrations.calibrations[idx + 1 :],
current_calibrations.measure_calibrations,
)

self._program.calibrations = new_calibrations
elif isinstance(instruction, DefMeasureCalibration):

elif instruction.is_measure_calibration_definition():
defmeasure = instruction.to_measure_calibration_definition()
idx, existing_measure_calibration = next(
(
(i, measurement)
for i, measurement in enumerate(self.measure_calibrations)
if (measurement.memory_reference == instruction.memory_reference)
and (measurement.qubit == instruction.qubit)
(i, existing_measure_calibration)
for i, existing_measure_calibration in enumerate(self._program.calibrations.measure_calibrations)
if existing_measure_calibration.parameter == defmeasure.parameter
and existing_measure_calibration.qubit == defmeasure.qubit
),
(0, None),
)
if existing_measure_calibration is None:
self._program.add_instruction(_convert_to_rs_instruction(instruction))
self._program.add_instruction(instruction)

else:
warnings.warn("Redefining DefMeasureCalibration {}".format(instruction))
current_calibrations = self._program.calibrations
new_calibrations = CalibrationSet(
current_calibrations.calibrations,
current_calibrations.measure_calibrations[:idx]
+ [instruction]
+ [defmeasure]
+ current_calibrations.measure_calibrations[idx + 1 :],
)

Expand Down
3 changes: 0 additions & 3 deletions test/unit/test_quil.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ def test_defgate_param(snapshot):
assert tg.out() == snapshot


# TODO: Automatically re-define existing definitions quil-rs#224
def test_defgate_redefintion():
"""Test that adding a defgate with the same name updates the definition."""
program = Program()
Expand All @@ -151,7 +150,6 @@ def test_defgate_redefintion():
assert np.all(program.defined_gates[0].matrix == new_mat)


# TODO: Automatically re-define existing definitions quil-rs#224
def test_defcal_redefinition(snapshot: SnapshotAssertion):
"""Test that adding a defcalibration with the same name updates the definition."""
program = Program()
Expand All @@ -172,7 +170,6 @@ def test_defcal_redefinition(snapshot: SnapshotAssertion):
assert program.calibrations[0].instrs[0].out() == snapshot


# TODO: Automatically re-define existing definitions quil-rs#224
def test_defcalmeasure_redefinition(snapshot: SnapshotAssertion):
"""Test that adding a defcalibration with the same name updates the definition."""
program = Program()
Expand Down

0 comments on commit 9349b7c

Please sign in to comment.