Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pam verify #196

Merged
merged 25 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d7b9939
Implemented update_error_mul
edyounis Oct 2, 2023
6885a78
Fixed tagged gate with dict data
edyounis Oct 2, 2023
ff8180a
ForEach always updates error now
edyounis Oct 2, 2023
c049570
Circuit append methods now return cycle of new op
edyounis Oct 2, 2023
64734ac
PAM now stores select data per block
edyounis Oct 2, 2023
09a6766
Implemented PAMVerificationSequence and helpers
edyounis Oct 2, 2023
a0cb964
Added PAM workflow factory with verification
edyounis Oct 2, 2023
2f50ec8
Added PAM Verification Test
edyounis Oct 2, 2023
3615da4
Added OTS compilation test
edyounis Oct 2, 2023
de93b98
pre-commit
edyounis Oct 2, 2023
ad12356
Small fix to make PAM work for different gate sets
jkalloor3 Oct 5, 2023
75f990e
Merge pull request #190 from jkalloor3/pam-verify
edyounis Oct 15, 2023
ae1dffa
More clearly defined the roles of some data vars
edyounis Oct 15, 2023
d7ae7cb
Update use of data vars
edyounis Oct 15, 2023
d020a20
All single-qudit gate blocks always executable
edyounis Oct 15, 2023
26a5025
Updated pam workflow
edyounis Oct 15, 2023
4e0f8e0
Fixed issues with pam-verify
edyounis Oct 15, 2023
2d501a5
pre-commit
edyounis Oct 15, 2023
10b2c18
Fixed mapping issue
edyounis Oct 16, 2023
a803bde
More testing
edyounis Oct 16, 2023
a5a224d
Update tests
edyounis Oct 16, 2023
b94ce8f
Removed error case in append_circuit
edyounis Oct 17, 2023
a266443
Updated sabre test with apply placement
edyounis Oct 17, 2023
89fac09
pre-commit
edyounis Oct 17, 2023
34114b6
Merge pull request #192 from BQSKit/pam-verify-bug-fixes
edyounis Oct 17, 2023
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
220 changes: 145 additions & 75 deletions bqskit/compiler/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@
from bqskit.passes.mapping.placement.greedy import GreedyPlacementPass
from bqskit.passes.mapping.routing.pam import PAMRoutingPass
from bqskit.passes.mapping.routing.sabre import GeneralizedSabreRoutingPass
from bqskit.passes.mapping.setmodel import ExtractModelConnectivityPass
from bqskit.passes.mapping.setmodel import RestoreModelConnevtivityPass
from bqskit.passes.mapping.setmodel import SetModelPass
from bqskit.passes.mapping.topology import SubtopologySelectionPass
from bqskit.passes.mapping.verify import PAMVerificationSequence
from bqskit.passes.measure import ExtractMeasurements
from bqskit.passes.measure import RestoreMeasurements
from bqskit.passes.noop import NOOPPass
Expand Down Expand Up @@ -1128,6 +1131,142 @@ def build_sabre_mapping_workflow() -> Workflow:
)


def build_seqpam_mapping_optimization_workflow(
optimization_level: int = 4,
synthesis_epsilon: float = 1e-8,
num_layout_passes: int = 3,
block_size: int = 3,
error_sim_size: int | None = None,
) -> Workflow:
"""
Build a Sequential-Permutation-Aware Mapping and Optimizing Workflow.

Note:
- This workflow assumes that SetModelPass will be run earlier in the
full workflow and doesn't add it in here.

- This will apply the placement found during the workflow. The
resulting circuit will be physically mapped.

Args:
optimization_level (int): The optimization level. See :func:`compile`
for more information.

synthesis_epsilon (float): The maximum distance between target
and circuit unitary allowed to declare successful synthesis.
Set to 0 for exact synthesis. (Default: 1e-8)

num_layout_passes (int): The number of layout forward and backward
passes to run. See :class:`PamLayoutPass` for more information.
(Default: 3)

block_size (int): The size of the blocks to partition into.
Warning, the number of permutation evaluated increases
factorially and the difficulty of each permutation increases
exponentially with this. (Default: 3)

error_sim_size (int | None): The size of the blocks to simulate
errors on. If None, then no error analysis is performed.
(Default: None)

Raises:
ValueError: If block_size < 2.

ValueError: If error_sim_size < block_size.
"""
if not is_integer(block_size):
raise TypeError(
f'Expected block_size to be int, got {type(block_size)}.',
)

if block_size < 2:
raise ValueError(f'Expected block_size > 1, got {block_size}.')

if error_sim_size is not None and not is_integer(block_size):
raise TypeError(
f'Expected int for error_sim_size, got {type(error_sim_size)}.',
)

if error_sim_size is not None and error_sim_size < block_size:
raise ValueError(
f'Expected error_sim_size >= block_size, got {error_sim_size}.',
)

qsearch = QSearchSynthesisPass(
success_threshold=synthesis_epsilon,
instantiate_options=get_instantiate_options(optimization_level),
)

leap = LEAPSynthesisPass(
success_threshold=synthesis_epsilon,
min_prefix_size=9,
instantiate_options=get_instantiate_options(optimization_level),
)

if error_sim_size is not None:
post_pam_seq: BasePass = PAMVerificationSequence(error_sim_size)
else:
post_pam_seq = NOOPPass()

return Workflow(
IfThenElsePass(
NotPredicate(WidthPredicate(2)),
[
ExtractModelConnectivityPass(),
QuickPartitioner(block_size),
ForEachBlockPass(
IfThenElsePass(
WidthPredicate(4),
EmbedAllPermutationsPass(
inner_synthesis=qsearch,
input_perm=True,
output_perm=False,
vary_topology=False,
),
EmbedAllPermutationsPass(
inner_synthesis=leap,
input_perm=True,
output_perm=False,
vary_topology=False,
),
),
),
PAMRoutingPass(),
post_pam_seq,
UnfoldPass(),
RestoreModelConnevtivityPass(),

SubtopologySelectionPass(block_size),
QuickPartitioner(block_size),
ForEachBlockPass(
IfThenElsePass(
WidthPredicate(4),
EmbedAllPermutationsPass(
inner_synthesis=qsearch,
input_perm=False,
output_perm=True,
vary_topology=True,
),
EmbedAllPermutationsPass(
inner_synthesis=leap,
input_perm=False,
output_perm=True,
vary_topology=True,
),
),
),
ApplyPlacement(),
PAMLayoutPass(num_layout_passes),
PAMRoutingPass(0.1),
post_pam_seq,
ApplyPlacement(),
UnfoldPass(),
],
),
name='SeqPAM Mapping',
)


def build_gate_deletion_optimization_workflow(
optimization_level: int = 1,
synthesis_epsilon: float = 1e-8,
Expand Down Expand Up @@ -1370,89 +1509,20 @@ def _opt4_workflow(
error_sim_size: int = 8,
) -> list[BasePass]:
"""Build optimization Level 4 workflow for circuit compilation."""
if error_threshold is not None:
_logger.warning(
'Automated error upper bound calculated is not yet'
' ready for opt level 4.',
)

if max_synthesis_size > 3:
_logger.warning(
'It is currently recommended to set max_synthesis_size to 3'
' for optimization level 4. This may change in the future.',
)

qsearch = QSearchSynthesisPass(
success_threshold=synthesis_epsilon,
instantiate_options=get_instantiate_options(4),
)
leap = LEAPSynthesisPass(
success_threshold=synthesis_epsilon,
min_prefix_size=9,
instantiate_options=get_instantiate_options(4),
)

return [
SetModelPass(
MachineModel(
model.num_qudits,
None,
model.gate_set,
model.radixes,
),
),
Workflow(
IfThenElsePass(
NotPredicate(WidthPredicate(2)),
[
QuickPartitioner(3),
ForEachBlockPass(
IfThenElsePass(
WidthPredicate(4),
EmbedAllPermutationsPass(
inner_synthesis=qsearch,
input_perm=True,
output_perm=False,
vary_topology=False,
),
EmbedAllPermutationsPass(
inner_synthesis=leap,
input_perm=True,
output_perm=False,
vary_topology=False,
),
),
),
PAMRoutingPass(),
UnfoldPass(),
SetModelPass(model),

SetModelPass(model),
SubtopologySelectionPass(3),
QuickPartitioner(3),
ForEachBlockPass(
IfThenElsePass(
WidthPredicate(4),
EmbedAllPermutationsPass(
inner_synthesis=qsearch,
input_perm=False,
output_perm=True,
vary_topology=True,
),
EmbedAllPermutationsPass(
inner_synthesis=leap,
input_perm=False,
output_perm=True,
vary_topology=True,
),
),
),
ApplyPlacement(),
PAMLayoutPass(3),
PAMRoutingPass(0.1),
UnfoldPass(),
],
),
name='SeqPAM Mapping',
build_seqpam_mapping_optimization_workflow(
4,
synthesis_epsilon,
block_size=max_synthesis_size,
error_sim_size=None if error_threshold is None else error_sim_size,
),

build_multi_qudit_retarget_workflow(
Expand Down
18 changes: 16 additions & 2 deletions bqskit/compiler/passdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ def placement(self, _val: Sequence[int]) -> None:

@property
def initial_mapping(self) -> list[int]:
"""Return the initial mapping of logical to physical qudits."""
"""
Return the initial mapping of logical to physical qudits.

This always maps how the logical qudits from the original circuit start
on the physical qudits of the current circuit.
"""
return self._initial_mapping

@initial_mapping.setter
Expand All @@ -166,7 +171,12 @@ def initial_mapping(self, _val: Sequence[int]) -> None:

@property
def final_mapping(self) -> list[int]:
"""Return the final mapping of logical to physical qudits."""
"""
Return the final mapping of logical to physical qudits.

This always maps how the logical qudits from the original circuit end on
the physical qudits of the current circuit.
"""
return self._final_mapping

@final_mapping.setter
Expand Down Expand Up @@ -262,3 +272,7 @@ def become(self, other: PassData, deepcopy: bool = False) -> None:
self._placement = copy.copy(other._placement)
self._data = copy.copy(other._data)
self._seed = copy.copy(other._seed)

def update_error_mul(self, error: float) -> None:
"""Update the error multiplicatively."""
self.error = (1 - ((1 - self.error) * (1 - error)))
33 changes: 25 additions & 8 deletions bqskit/ir/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,13 +1035,16 @@ def point(

raise ValueError('No such operation exists in the circuit.')

def append(self, op: Operation) -> None:
def append(self, op: Operation) -> int:
"""
Append `op` to the end of the circuit.
Append `op` to the end of the circuit and return its cycle index.

Args:
op (Operation): The operation to append.

Returns:
int: The cycle index of the appended operation.

Raises:
ValueError: If `op` cannot be placed on the circuit due to
either an invalid location or gate radix mismatch.
Expand Down Expand Up @@ -1093,12 +1096,14 @@ def append(self, op: Operation) -> None:
self._gate_info[op.gate] = 0
self._gate_info[op.gate] += 1

return cycle_index

def append_gate(
self,
gate: Gate,
location: CircuitLocationLike,
params: RealVector = [],
) -> None:
) -> int:
"""
Append the gate object to the circuit on the qudits in location.

Expand All @@ -1110,6 +1115,9 @@ def append_gate(
params (RealVector): The gate's parameters.
(Default: all zeros)

Returns:
int: The cycle index of the appended gate.

Examples:
>>> from bqskit.ir.gates import HGate
>>> circ = Circuit(1)
Expand All @@ -1119,15 +1127,15 @@ def append_gate(
See Also:
:func:`append`
"""
self.append(Operation(gate, location, params))
return self.append(Operation(gate, location, params))

def append_circuit(
self,
circuit: Circuit,
location: CircuitLocationLike,
as_circuit_gate: bool = False,
move: bool = False,
) -> None:
) -> int:
"""
Append `circuit` at the qudit location specified.

Expand All @@ -1143,6 +1151,10 @@ def append_circuit(
move (bool): Move circuit into circuit gate rather than copy.
(Default: False)

Returns:
int: The starting cycle index of the appended circuit. If the
appended circuit is empty, then this will be -1.

Raises:
ValueError: If `circuit` is not the same size as `location`.

Expand All @@ -1165,12 +1177,17 @@ def append_circuit(

if as_circuit_gate:
op = Operation(CircuitGate(circuit, move), location, circuit.params)
self.append(op)
return
return self.append(op)

cycle_index = -1

for op in circuit:
mapped_location = [location[q] for q in op.location]
self.append(Operation(op.gate, mapped_location, op.params))
ci = self.append(Operation(op.gate, mapped_location, op.params))
if cycle_index is None:
cycle_index = ci

return cycle_index

def extend(self, ops: Iterable[Operation]) -> None:
"""
Expand Down
3 changes: 3 additions & 0 deletions bqskit/ir/gates/composed/tagged.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,7 @@ def __eq__(self, other: object) -> bool:
)

def __hash__(self) -> int:
if isinstance(self.tag, dict):
return hash((self.gate, tuple(self.tag.items())))

return hash((self.gate, self.tag))
Loading
Loading