Skip to content

Commit

Permalink
Add construct module
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikandreasseitz committed Oct 16, 2023
1 parent e23b9ba commit cab29b9
Show file tree
Hide file tree
Showing 17 changed files with 166 additions and 184 deletions.
6 changes: 1 addition & 5 deletions qadence/blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
ControlBlock,
)
from .composite import AddBlock, ChainBlock, CompositeBlock, KronBlock, PutBlock
from .construct import add, chain, kron, tag, put
from .matrix import MatrixBlock
from .manipulate import from_openfermion, to_openfermion
from .utils import (
add,
chain,
kron,
tag,
put,
block_is_commuting_hamiltonian,
block_is_qubit_hamiltonian,
parameters,
Expand Down
20 changes: 10 additions & 10 deletions qadence/blocks/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ def __eq__(self, other: object) -> bool:
pass

def __mul__(self, other: Union[AbstractBlock, TNumber, Parameter]) -> AbstractBlock:
from qadence.blocks.construct import chain
from qadence.blocks.primitive import ScaleBlock
from qadence.blocks.utils import chain

# TODO: Improve type checking here
if isinstance(other, AbstractBlock):
Expand All @@ -95,8 +95,8 @@ def __rmul__(self, other: AbstractBlock | TNumber | Parameter) -> AbstractBlock:

def __imul__(self, other: Union[AbstractBlock, TNumber, Parameter]) -> AbstractBlock:
from qadence.blocks.composite import ChainBlock
from qadence.blocks.construct import chain
from qadence.blocks.primitive import ScaleBlock
from qadence.blocks.utils import chain

if not isinstance(other, AbstractBlock):
raise TypeError("In-place multiplication is available only for AbstractBlock instances")
Expand All @@ -121,14 +121,14 @@ def __truediv__(self, other: Union[TNumber, sympy.Basic]) -> AbstractBlock:
return self * ix

def __add__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.utils import add
from qadence.blocks.construct import add

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only add a block to another block. Got {type(other)}.")
return add(self, other)

def __radd__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.utils import add
from qadence.blocks.construct import add

if isinstance(other, int) and other == 0:
return self
Expand All @@ -138,7 +138,7 @@ def __radd__(self, other: AbstractBlock) -> AbstractBlock:

def __iadd__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.composite import AddBlock
from qadence.blocks.utils import add
from qadence.blocks.construct import add

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only add a block to another block. Got {type(other)}.")
Expand All @@ -151,8 +151,8 @@ def __iadd__(self, other: AbstractBlock) -> AbstractBlock:
)

def __sub__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.construct import add
from qadence.blocks.primitive import ScaleBlock
from qadence.blocks.utils import add

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only subtract a block from another block. Got {type(other)}.")
Expand All @@ -165,7 +165,7 @@ def __sub__(self, other: AbstractBlock) -> AbstractBlock:

def __isub__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.composite import AddBlock
from qadence.blocks.utils import add
from qadence.blocks.construct import add

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only add a block to another block. Got {type(other)}.")
Expand All @@ -178,7 +178,7 @@ def __isub__(self, other: AbstractBlock) -> AbstractBlock:
)

def __pow__(self, power: int) -> AbstractBlock:
from qadence.blocks.utils import chain
from qadence.blocks.construct import chain

return chain(self for _ in range(power))

Expand All @@ -189,15 +189,15 @@ def __pos__(self) -> AbstractBlock:
return self

def __matmul__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.utils import kron
from qadence.blocks.construct import kron

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only kron a block to another block. Got {type(other)}.")
return kron(self, other)

def __imatmul__(self, other: AbstractBlock) -> AbstractBlock:
from qadence.blocks.composite import KronBlock
from qadence.blocks.utils import kron
from qadence.blocks.construct import kron

if not isinstance(other, AbstractBlock):
raise TypeError(f"Can only kron a block with another block. Got {type(other)}.")
Expand Down
3 changes: 2 additions & 1 deletion qadence/blocks/block_to_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
PrimitiveBlock,
ScaleBlock,
)
from qadence.blocks.utils import chain, kron, uuid_to_expression
from qadence.blocks.construct import chain, kron
from qadence.blocks.utils import uuid_to_expression
from qadence.parameters import evaluate, stringify
from qadence.types import Endianness, TensorType, TNumber

Expand Down
2 changes: 1 addition & 1 deletion qadence/blocks/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def _to_dict(self) -> dict:
def _from_dict(cls, d: dict) -> CompositeBlock:
from qadence import blocks as qadenceblocks
from qadence import operations
from qadence.blocks.utils import _construct, tag
from qadence.blocks.construct import _construct, tag

blocks = [
getattr(operations, b["type"])._from_dict(b)
Expand Down
128 changes: 128 additions & 0 deletions qadence/blocks/construct.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from __future__ import annotations

from typing import Generator, List, Type, TypeVar, Union

from qadence.blocks import (
AbstractBlock,
AddBlock,
ChainBlock,
CompositeBlock,
KronBlock,
PrimitiveBlock,
PutBlock,
)
from qadence.blocks.analog import AnalogBlock, AnalogComposite
from qadence.blocks.analog import chain as analog_chain
from qadence.blocks.analog import kron as analog_kron
from qadence.logger import get_logger

logger = get_logger(__name__)


TPrimitiveBlock = TypeVar("TPrimitiveBlock", bound=PrimitiveBlock)
TCompositeBlock = TypeVar("TCompositeBlock", bound=CompositeBlock)


def _construct(
Block: Type[TCompositeBlock],
args: tuple[Union[AbstractBlock, Generator, List[AbstractBlock]], ...],
) -> TCompositeBlock:
if len(args) == 1 and isinstance(args[0], Generator):
args = tuple(args[0])
return Block([b for b in args]) # type: ignore [arg-type]


def chain(*args: Union[AbstractBlock, Generator, List[AbstractBlock]]) -> ChainBlock:
"""Chain blocks sequentially. On digital backends this can be interpreted
loosely as a matrix mutliplication of blocks. In the analog case it chains
blocks in time.
Arguments:
*args: Blocks to chain. Can also be a generator.
Returns:
ChainBlock
Example:
```python exec="on" source="material-block" result="json"
from qadence import X, Y, chain
b = chain(X(0), Y(0))
# or use a generator
b = chain(X(i) for i in range(3))
print(b)
```
"""
# ugly hack to use `AnalogChain` if we are dealing only with analog blocks
if len(args) and all(
isinstance(a, AnalogBlock) or isinstance(a, AnalogComposite) for a in args
):
return analog_chain(*args) # type: ignore[return-value,arg-type]
return _construct(ChainBlock, args)


def kron(*args: Union[AbstractBlock, Generator]) -> KronBlock:
"""Stack blocks vertically. On digital backends this can be intepreted
loosely as a kronecker product of blocks. In the analog case it executes
blocks parallel in time.
Arguments:
*args: Blocks to kron. Can also be a generator.
Returns:
KronBlock
Example:
```python exec="on" source="material-block" result="json"
from qadence import X, Y, kron
b = kron(X(0), Y(1))
# or use a generator
b = kron(X(i) for i in range(3))
print(b)
```
"""
# ugly hack to use `AnalogKron` if we are dealing only with analog blocks
if len(args) and all(
isinstance(a, AnalogBlock) or isinstance(a, AnalogComposite) for a in args
):
return analog_kron(*args) # type: ignore[return-value,arg-type]
return _construct(KronBlock, args)


def add(*args: Union[AbstractBlock, Generator]) -> AddBlock:
"""Sums blocks.
Arguments:
*args: Blocks to add. Can also be a generator.
Returns:
AddBlock
Example:
```python exec="on" source="material-block" result="json"
from qadence import X, Y, add
b = add(X(0), Y(0))
# or use a generator
b = add(X(i) for i in range(3))
print(b)
```
"""
return _construct(AddBlock, args)


def tag(block: AbstractBlock, tag: str) -> AbstractBlock:
block.tag = tag
return block


def put(block: AbstractBlock, min_qubit: int, max_qubit: int) -> PutBlock:
from qadence.transpile import reassign

support = tuple(range(min(block.qubit_support), max(block.qubit_support) + 1))
shifted_block = reassign(block, {i: i - min(support) for i in support})
return PutBlock(shifted_block, tuple(range(min_qubit, max_qubit + 1)))
2 changes: 1 addition & 1 deletion qadence/blocks/manipulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from qadence import operations
from qadence.blocks import AbstractBlock, AddBlock, CompositeBlock, PrimitiveBlock, ScaleBlock
from qadence.blocks.utils import add, kron
from qadence.blocks.construct import add, kron
from qadence.parameters import evaluate


Expand Down
2 changes: 1 addition & 1 deletion qadence/blocks/primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def __init__(self, block: AbstractBlock, parameter: Any):
super().__init__(block.qubit_support)

def __pow__(self, power: int) -> AbstractBlock:
from qadence.blocks.utils import chain
from qadence.blocks.construct import chain

expr = self.parameters.parameter
return ScaleBlock(chain(self.block for _ in range(power)), expr**power)
Expand Down
Loading

0 comments on commit cab29b9

Please sign in to comment.