Skip to content
Merged
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
84 changes: 84 additions & 0 deletions docs/examples/qpe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
description: Program representing QPE using geometric sequence
input:
program:
children:
- name: Hadamards
ports:
- direction: through
name: register
size: N
- name: Evolution
ports:
- direction: input
name: result_in
size: bits_of_precision
- direction: output
name: result_out
size: N
- direction: input
name: psi_in
size: None
- direction: output
name: psi_out
size: None
children:
- name: U
ports:
- direction: through
name: result
size: bits_of_precision
- direction: through
name: psi
size: N
resources:
- name: T_gates
type: additive
value: N**2
connections:
- source: result_in
target: U.result
- source: U.result
target: result_out
- source: psi_in
target: U.psi
- source: U.psi
target: psi_out
repetition:
count: bits_of_precision
sequence:
type: geometric
ratio: 1
- name: Inverse_QFT
ports:
- direction: through
name: register
size: N
connections:
- source: result_in
target: Hadamards.register
- source: Hadamards.register
target: Evolution.result_in
- source: Evolution.result_out
target: Inverse_QFT.register
- source: Inverse_QFT.register
target: result_out
- source: psi_in
target: Evolution.psi_in
- source: Evolution.psi_out
target: psi_out
name: QPE
ports:
- direction: input
name: result_in
size: ceil(log2(1/eps))
- direction: output
name: result_out
size: ceil(log2(1/eps))
- direction: input
name: psi_in
size: M
- direction: output
name: psi_out
size: M

version: v1
42 changes: 42 additions & 0 deletions docs/format.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,45 @@ beginning looks as follows:
```yaml
--8<-- "basic_program_concise.yaml"
```


### Repetitions

On top of the basic fileds listed above, one can also write a QREF routine which contains repetitions.

This can be added with `repetition` field:

```yaml
repetition:
count: ceil(1/eps)
sequence:
type: constant
multiplier: 1
```

`repetition` consists of two parts:

- `count` – defines how many times the child of the this routine should be repeated.
- `sequence` – defines how the costs for the repetition will be aggregated. Each `sequence` has a field `type` which defines the type of the sequence. Depending on the type there are extra fields, summarized in the table below.


There are 5 different sequences that one can currently use in QREF:


| <div style="width:7em">Sequence type</div> | <div style="width:8em">Additional fields</div> | Description | Example |
|-------|-------|-------|-------|
| `constant`| `multiplier` | In each iteration child is repeated `multiplier` number of times. | Trotterization |
| `arithmetic`| `difference`, `initial_term` | Iteration starts from `initial_term` repetitions of a child and then we increase the of repetitions by `difference` in every iteration. | QFT |
| `geometric` | `ratio` | In each iteration number of repetitions is multiplied by `ratio`, starts for 1 repetition in the first iteartion. | QPE |
| `closed_form` | `sum`, `prod`, `num_terms_symbol` | This can be used for cases, where we know the closed-form expression for the total cost of the routine given the number of repetitions is defined `num_terms_symbol`. `sum` is an expression for additive resources and `prod` is for multiplicative. | Any |
| `custom` | `term_expression`, `iterator_symbol` | This can be used in case where we don't know the formula for closed form, but we do know the formula for each term, which is defined using `term_expression`, and we use `iterator_symbol` to denote the iterator. | Any |


This representation abstracts out certain implementation details. Consider implementation of QPE using geometric sequence below. The child `U` of routine `Evolution` has two ports: `result` and `psi`, the with sizes `bits_of_precision` and `N`. Even though in the executable implementation each next controlled `U^2^i` only acts on one control qubit from the `result` register, there's currently no way of expressing it in QREF.

=== "YAML"

```yaml
--8<-- "qpe.yaml"
```

89 changes: 76 additions & 13 deletions src/qref/schema_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,27 +167,90 @@ class ParamLinkV1(BaseModel):
model_config = ConfigDict(title="ParamLink")


class ConstantSequenceV1(BaseModel):
"""Description of a constant sequence in a V1 Schema.

In a constant sequence we repeat an element `multiplier` times in each iteration.
"""

type: Literal["constant"]
multiplier: _Value = 1


class ArithmeticSequenceV1(BaseModel):
"""Description of an arithmetic sequence in a V1 Schema.

In an arithmetic sequence we start from `initial_term` repetitions of an element,
and in each iteration we increase it by `difference`.
"""

type: Literal["arithmetic"]
initial_term: _Value = 0
difference: _Value


class GeometricSequenceV1(BaseModel):
"""Description of a geometric sequence in a V1 Schema.

In a geometric sequence we start from 1 repetition of an element,
and in each iteration we multiply it by `ratio`.
"""

type: Literal["geometric"]
ratio: _Value


class ClosedFormSequenceV1(BaseModel):
"""Description of a sequence with known closed-form for a sum or product in a V1 Schema.

If `sum`/`prod` are specified, they can be used to calculate these values for a given sequence.
Expressions for `sum`/`prod` should use `num_terms_symbol` to represent the total number of terms.
"""

type: Literal["closed_form"]
sum: _Value | None = None
prod: _Value | None = None
num_terms_symbol: str


class CustomSequenceV1(BaseModel):
"""Description of a custom sequence in a V1 Schema.

For sequences which do not fall into categories defined in other classes, one can use a custom representation.
It is an explicit representation of a sequence where `term_expression` defines the expression for each term
in the sequence and `iterator_symbol` is used to represent number of the iteration.
"""

type: Literal["custom"]
term_expression: str
iterator_symbol: str = "i"


class RepetitionV1(BaseModel):
"""Description of a repetition of a routine in V1 schema."""

count: int | str
sequence: ConstantSequenceV1 | ArithmeticSequenceV1 | GeometricSequenceV1 | ClosedFormSequenceV1 | CustomSequenceV1


class RoutineV1(BaseModel):
"""Description of Routine in V1 schema.

Note:
This is NOT a top-level object in the schema. Instead, RoutineV1 is wrapped in
SchemaV1.
This is NOT a top-level object in the schema. Instead, RoutineV1 is wrapped in SchemaV1.
"""

name: _Name
children: Annotated[NamedList[RoutineV1], _name_sorter] = Field(default_factory=list)
children: Annotated[NamedList[RoutineV1], _name_sorter] = Field(default_factory=NamedList)
type: str | None = None
ports: Annotated[NamedList[PortV1], _name_sorter] = Field(default_factory=list)
resources: Annotated[NamedList[ResourceV1], _name_sorter] = Field(default_factory=list)
connections: Annotated[list[Annotated[ConnectionV1, _connection_parser]], _source_sorter] = Field(
default_factory=list
)
input_params: list[_OptionallyMultiNamespacedName] = Field(default_factory=list)
local_variables: dict[str, str] = Field(default_factory=dict)
linked_params: Annotated[list[ParamLinkV1], _source_sorter] = Field(default_factory=list)
meta: dict[str, Any] = Field(default_factory=dict)

ports: Annotated[NamedList[PortV1], _name_sorter] = Field(default_factory=NamedList)
resources: Annotated[NamedList[ResourceV1], _name_sorter] = Field(default_factory=NamedList)
connections: Annotated[list[Annotated[ConnectionV1, _connection_parser]], _source_sorter] = []
input_params: list[_OptionallyMultiNamespacedName] = []
local_variables: dict[str, str] = {}
linked_params: Annotated[list[ParamLinkV1], _source_sorter] = []
repetition: RepetitionV1 | None = None
meta: dict[str, Any] = {}
model_config = ConfigDict(title="Routine", validate_assignment=True)

def __init__(self, **data: Any):
Expand Down
4 changes: 1 addition & 3 deletions src/qref/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ def _dfs_iteration(adjacency_list: AdjacencyList, start_node: str, ancestor_path
visited: list[str] = []
predecessors: dict[str, str] = {}

_prefix = _make_prefixer(ancestor_path)

while to_visit:
node = to_visit.pop()
visited.append(node)
Expand All @@ -131,7 +129,7 @@ def _dfs_iteration(adjacency_list: AdjacencyList, start_node: str, ancestor_path
# Reconstruct the cycle
cycle = [neighbour]
while len(cycle) < 2 or cycle[-1] != start_node:
cycle.append(_prefix(predecessors[cycle[-1]]))
cycle.append(predecessors[cycle[-1]])
return [f"Cycle detected: {cycle[::-1]}"]
if neighbour not in visited:
to_visit.append(neighbour)
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


def _load_valid_examples():
for path in sorted(VALID_PROGRAMS_ROOT_PATH.iterdir()):
for path in sorted(VALID_PROGRAMS_ROOT_PATH.rglob("*.yaml")):
with open(path) as f:
data = yaml.safe_load(f)
yield pytest.param(data["input"], id=data["description"])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
description: Program with one subroutine repeated multiple times
input:
program:
children:
- name: A
ports:
- direction: through
name: port_A
size: N
- name: B
input_params:
- eps
linked_params:
- source: eps
targets:
- core_subroutine.eps
ports:
- direction: input
name: port_B_in
size: N
- direction: output
name: port_B_out
size: N
children:
- name: core_subroutine
input_params:
- eps
ports:
- direction: through
name: my_port
size: N
resources:
- name: cost
type: additive
value: ceil(1/eps)/2
connections:
- source: port_B_in
target: core_subroutine.my_port
- source: core_subroutine.my_port
target: port_B_out
repetition:
count: ceil(1/eps)
sequence:
type: constant
multiplier: 1
- name: C
ports:
- direction: through
name: port_C
size: N
connections:
- source: in_0
target: A.port_A
- source: A.port_A
target: B.port_B_in
- source: B.port_B_out
target: C.port_C
- source: C.port_C
target: out_0
input_params:
- N
linked_params:
- source: N
targets:
- B.eps
name: root
ports:
- direction: input
name: in_0
size: N
- direction: output
name: out_0
size: N
version: v1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
description: Program representing QFT using arithmetic sequence.
input:
program:
children:
- name: QFT_iterate
ports:
- direction: input
name: in_0
size: N
- direction: output
name: out_0
size: N
children:
- name: core_subroutine
ports:
- direction: through
name: my_port
size: N
resources:
- name: rotations
type: additive
value: N
connections:
- source: in_0
target: core_subroutine.my_port
- source: core_subroutine.my_port
target: out_0
repetition:
count: N
sequence:
type: arithmetic
difference: 1
connections:
- source: in_0
target: QFT_iterate.in_0
- source: QFT_iterate.out_0
target: out_0
name: QFT
ports:
- direction: input
name: in_0
size: N
- direction: output
name: out_0
size: N
version: v1
Loading