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

Migrate StrategyExecutor to new transformer infrastructure #5644

Merged
merged 20 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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 cirq-core/cirq/contrib/acquaintance/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
AcquaintanceOperation,
GreedyExecutionStrategy,
StrategyExecutor,
StrategyExecutorTransformer,
)

from cirq.contrib.acquaintance.gates import acquaint, AcquaintanceOpportunityGate, SwapNetworkGate
Expand Down
86 changes: 80 additions & 6 deletions cirq-core/cirq/contrib/acquaintance/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import DefaultDict, Dict, Sequence, TYPE_CHECKING, Optional
from typing import DefaultDict, Dict, Sequence, Optional
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved

import abc
from collections import defaultdict

from cirq import circuits, devices, ops, protocols
from cirq import circuits, devices, ops, protocols, transformers
import cirq
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved

from cirq.contrib.acquaintance.gates import AcquaintanceOpportunityGate
from cirq.contrib.acquaintance.permutation import (
Expand All @@ -29,9 +30,6 @@
)
from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates

if TYPE_CHECKING:
import cirq

ammareltigani marked this conversation as resolved.
Show resolved Hide resolved

class ExecutionStrategy(metaclass=abc.ABCMeta):
"""Tells StrategyExecutor how to execute an acquaintance strategy.
Expand Down Expand Up @@ -61,9 +59,26 @@ def get_operations(
"""Gets the logical operations to apply to qubits."""

def __call__(self, *args, **kwargs):
return StrategyExecutor(self)(*args, **kwargs)
"""Returns a copy of the modified circuit and the final mapping of
logical indices to qubits
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
"""
if not isinstance(args[0], circuits.AbstractCircuit):
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError(
(
"To call ExecutionStrategy, an argument of type "
"'cirq.Circuit' must be passed in as the first non-keyword argument"
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
)
)
input_circuit = args[0]
strategy = StrategyExecutorTransformer(self)
final_circuit = strategy(input_circuit, **kwargs)
input_circuit._moments = final_circuit._moments
return strategy.get_mapping()


@cirq._compat.deprecated_class(
deadline='v1.0', fix='Use cirq.contrib.acquaintance.strategy_executor.'
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
)
class StrategyExecutor(circuits.PointOptimizer):
"""Executes an acquaintance strategy."""

Expand Down Expand Up @@ -100,6 +115,65 @@ def optimization_at(
)


class StrategyExecutorTransformer:
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
"""Executes an acquaintance strategy."""

def __init__(self, execution_strategy: ExecutionStrategy) -> None:
self.execution_strategy = execution_strategy
self.mapping = execution_strategy.initial_mapping.copy()

def __call__(
self, circuit: 'cirq.Circuit', context: Optional['cirq.TransformerContext'] = None
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
) -> circuits.AbstractCircuit:
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
"""Executes an acquaintance strategy using primitive map function and
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
mutates initial mapping.

Args:
circuit: Input circuit to transform.
context: `cirq.TransformerContext` storing common configurable
options for transformers.

Raises:
ValueError: if execution_strategy is None
TypeError: if execution_strategy neither an instance of
AcquaintanceOpportunityGate or PermutationGate
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved

Returns:
A copy of the modified circuit after executing an acquaintance
strategy on all instances of AcquaintanceOpportunityGate
"""

if self.execution_strategy is None:
raise ValueError('execution_strategy cannot be None')
expose_acquaintance_gates(circuit)
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
return transformers.map_operations(
circuit=circuit,
map_func=self.map_func,
deep=context.deep if context else False,
tags_to_ignore=context.tags_to_ignore if context else (),
)
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved

def get_mapping(self):
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
return self.mapping.copy()

def map_func(self, op: 'cirq.Operation', index) -> 'cirq.OP_TREE':
ammareltigani marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(op.gate, AcquaintanceOpportunityGate):
logical_indices = tuple(self.mapping[q] for q in op.qubits)
logical_operations = self.execution_strategy.get_operations(logical_indices, op.qubits)
clear_span = int(not self.execution_strategy.keep_acquaintance)
return logical_operations if clear_span else [op, logical_operations]

if isinstance(op.gate, PermutationGate):
op.gate.update_mapping(self.mapping, op.qubits)
return op

raise TypeError(
'Can only execute a strategy consisting of gates that '
'are instances of AcquaintanceOpportunityGate or '
'PermutationGate.'
)


class AcquaintanceOperation(ops.GateOperation):
"""Represents an a acquaintance opportunity between a particular set of
logical indices on a particular set of physical qubits.
Expand Down
5 changes: 4 additions & 1 deletion cirq-core/cirq/contrib/acquaintance/executor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ def test_executor_explicit():
}
initial_mapping = {q: i for i, q in enumerate(sorted(qubits))}
execution_strategy = cca.GreedyExecutionStrategy(gates, initial_mapping)
executor = cca.StrategyExecutor(execution_strategy)
with cirq.testing.assert_deprecated(
"Use cirq.contrib.acquaintance.strategy_executor", deadline='v1.0'
):
executor = cca.StrategyExecutor(execution_strategy)

with pytest.raises(NotImplementedError):
bad_gates = {(0,): ExampleGate(['0']), (0, 1): ExampleGate(['0', '1'])}
Expand Down