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

[WIP] Proof of Concept implementations for CompactLCU CompactState #6749

Open
wants to merge 3 commits into
base: trotter_resources
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions pennylane/labs/resource_estimation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
~ResourceAdjoint
~ResourceControlled
~ResourcePow
~ResourceProd

Templates
~~~~~~~~~
Expand Down Expand Up @@ -138,6 +139,7 @@

~ResourcesNotDefined
"""
from .compact_objects import CompactLCU, CompactState

from .resource_operator import ResourceOperator, ResourcesNotDefined
from .resource_tracking import DefaultGateSet, get_resources, resource_config
Expand Down Expand Up @@ -183,6 +185,7 @@
ResourceOrbitalRotation,
ResourcePauliRot,
ResourcePow,
ResourceProd,
ResourcePSWAP,
ResourcePhaseShift,
ResourceRot,
Expand Down
168 changes: 168 additions & 0 deletions pennylane/labs/resource_estimation/compact_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Copyright 2024 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module contains the base classes for compact hamiltonians and states
to be used with the existing resource estimation pipeline"""
import pennylane.numpy as qnp
from pennylane.labs import resource_estimation as re


class CompactLCU:
"""A class storing the meta data associated with an LCU decomposition of an operator."""

def __init__(
self,
num_wires,
lcu_type=None,
num_terms=None,
k_local=None,
cost_per_term=None,
cost_per_exp_term=None,
cost_per_ctrl_exp_term=None,
one_norm_error=None,
) -> None:
"""Store the meta info into the class attributes."""
self.num_wires = num_wires
self.lcu_type = lcu_type
self.num_terms = num_terms
self.k_local = k_local
self.cost_per_term = cost_per_term
self.cost_per_exp_term = cost_per_exp_term
self.cost_per_ctrl_exp_term = cost_per_ctrl_exp_term
self.one_norm_error = one_norm_error

def info(self, print_info=False):
"""Return a dictionary of the metadata or display it on screen."""
metadata_dict = self.__dict__

if print_info:
print(f"CompactLCU(num_wires={metadata_dict["num_wires"]}):")
for k, v in metadata_dict.items():
if k == "num_wires":
continue
print(f"-> {k}: {v}")

return metadata_dict

def update(self):
"""Update empty information after initializing the class."""
if self.lcu_type == "pauli":
cost_per_term = {}
x, y, z = (re.ResourceX.resource_rep(), re.ResourceY.resource_rep(), re.ResourceZ.resource_rep())

freq = self.k_local // 3

cost_per_term[x] = freq
cost_per_term[z] = freq
cost_per_term[y] = self.k_local - 2*freq

avg_pword = freq * "X" + freq * "Z" + (self.k_local - 2*freq) * "Y"
cost_per_exp_term = {re.ResourcePauliRot.resource_rep(avg_pword): 1}

if self.cost_per_term is None:
self.cost_per_term = cost_per_term

if self.cost_per_exp_term is None:
self.cost_per_exp_term = cost_per_exp_term

if self.lcu_type == "cdf":
cost_per_term = {}
cost_per_exp_term = {}
cost_per_ctrl_exp_term = {}

basis_rot = re.ResourceBasisRotation.resource_rep(self.num_wires)
adj_basis_rot = re.ResourceAdjoint.resource_rep(
re.ResourceBasisRotation, {"dim_N": self.num_wires}
)
z = re.ResourceZ.resource_rep()
multi_z = re.ResourceMultiRZ.resource_rep(2)
ctrl_multi_z = re.ResourceControlled.resource_rep(
re.ResourceMultiRZ, {"num_wires": 2}, 1, 0, 0
)

cost_per_term[basis_rot] = 2
cost_per_term[adj_basis_rot] = 2
cost_per_term[z] = 2

cost_per_exp_term[basis_rot] = 2
cost_per_exp_term[adj_basis_rot] = 2
cost_per_exp_term[multi_z] = 1

cost_per_ctrl_exp_term[basis_rot] = 2
cost_per_ctrl_exp_term[adj_basis_rot] = 2
cost_per_ctrl_exp_term[ctrl_multi_z] = 1

if self.cost_per_term is None:
self.cost_per_term = cost_per_term

if self.cost_per_exp_term is None:
self.cost_per_exp_term = cost_per_exp_term

if self.cost_per_ctrl_exp_term is None:
self.cost_per_ctrl_exp_term = cost_per_ctrl_exp_term

return


class CompactState:
"""A class storing the meta data associated with a quantum state."""

def __init__(
self,
num_wires,
data_size=None,
is_sparse=False,
is_bitstring=False,
precision=None,
num_aux_wires=None,
cost_per_prep=None,
cost_per_ctrl_prep=None,
) -> None:
self.num_wires = num_wires
self.data_size = data_size
self.is_sparse = is_sparse
self.is_bitstring = is_bitstring
self.precision = precision
self.num_aux_wires = num_aux_wires
self.cost_per_prep = cost_per_prep
self.cost_per_ctrl_prep = cost_per_ctrl_prep

def info(self, print_info=False):
"""Return a dictionary of the metadata or display it on screen."""
metadata_dict = self.__dict__

if print_info:
print(f"CompactState(num_wires={metadata_dict["num_wires"]}):")
for k, v in metadata_dict.items():
if k == "num_wires":
continue
print(f"-> {k}: {v}")

return metadata_dict

def update(self):
"""Update empty information after initializing the class."""
if (eps := self.precision) is not None:
n = self.num_wires
n_ctrl = n+1
t = re.ResourceT.resource_rep()

if self.cost_per_prep is None:
self.cost_per_prep = {t: self._qrom_state_prep(n, eps)}

if self.cost_per_ctrl_prep is None:
self.cost_per_ctrl_prep = {t: self._qrom_state_prep(n_ctrl, eps)}

@staticmethod
def _qrom_state_prep(n, eps):
return qnp.round(qnp.sqrt((2**n)*qnp.log(n/eps)) * n * qnp.log(n/eps) * qnp.log(1/eps))
1 change: 1 addition & 0 deletions pennylane/labs/resource_estimation/ops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,5 @@
ResourceControlled,
ResourceControlledPhaseShift,
ResourcePow,
ResourceProd,
)
28 changes: 28 additions & 0 deletions pennylane/labs/resource_estimation/ops/op_math/symbolic.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pennylane.ops.op_math.controlled import ControlledOp
from pennylane.ops.op_math.exp import Exp
from pennylane.ops.op_math.pow import PowOperation
from pennylane.ops.op_math.prod import Prod
from pennylane.ops.op_math.sprod import SProd

# pylint: disable=too-many-ancestors,arguments-differ,protected-access,too-many-arguments,too-many-positional-arguments
Expand Down Expand Up @@ -277,6 +278,33 @@ def controlled_resource_decomp(
raise re.ResourcesNotDefined


class ResourceProd(Prod, re.ResourceOperator):
"""Resource class for Prod"""

@classmethod
def _resource_decomp(cls, cmpr_reps, **kwargs) -> Dict[re.CompressedResourceOp, int]:
gate_types = defaultdict(int)

for op in cmpr_reps:
gate_types[op] += 1

return gate_types

def resource_params(self) -> dict:
ops = self.operands
cmpr_reps = tuple(op.resource_rep_from_op() for op in ops)
return {"cmpr_reps": cmpr_reps}

@classmethod
def resource_rep(cls, cmpr_reps) -> re.CompressedResourceOp:
return re.CompressedResourceOp(cls, {"cmpr_reps": cmpr_reps})

@staticmethod
def tracking_name(cmpr_reps) -> str:
base_names = [(cmpr_rep.op_type).tracking_name(**cmpr_rep.params) for cmpr_rep in cmpr_reps]
return f"Prod({",".join(base_names)})"


def _resources_from_pauli_word(pauli_word, num_wires):
pauli_string = "".join((str(v) for v in pauli_word.values()))
len_str = len(pauli_string)
Expand Down
4 changes: 2 additions & 2 deletions pennylane/labs/resource_estimation/resource_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from typing import Dict, Iterable, List, Set, Union

import pennylane as qml
from pennylane.operation import Operation
from pennylane.operation import Operation, Operator
from pennylane.queuing import AnnotatedQueue
from pennylane.tape import QuantumScript
from pennylane.wires import Wires
Expand Down Expand Up @@ -155,7 +155,7 @@ def my_circuit():

@get_resources.register
def resources_from_operation(
obj: Operation, gate_set: Set = DefaultGateSet, config: Dict = resource_config
obj: Operator, gate_set: Set = DefaultGateSet, config: Dict = resource_config
) -> Resources:
"""Get resources from an operation"""

Expand Down
Loading
Loading