Skip to content
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- **Greedy Scheduler**: Fast greedy scheduling algorithms as an alternative to CP-SAT optimization
- Added `greedy_minimize_time()` for minimal execution time scheduling with ALAP preparation optimization
- Added `greedy_minimize_space()` for minimal qubit usage scheduling

### Tests

- **Greedy Scheduler**: Added tests for greedy scheduling algorithms


## [0.2.1] - 2026-01-16

### Added
Expand Down
60 changes: 59 additions & 1 deletion graphqomb/feedforward.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
This module provides:

- `dag_from_flow`: Construct a directed acyclic graph (DAG) from a flowlike object.
- `inverse_dag_from_dag`: Construct an inverse DAG (node -> dependencies).
- `topo_order_from_inv_dag`: Construct a topological order from an inverse DAG.
- `check_dag`: Check if a directed acyclic graph (DAG) does not contain a cycle.
- `check_flow`: Check if the flowlike object is causal with respect to the graph state.
- `signal_shifting`: Convert the correction maps into more parallel-friendly forms using signal shifting.
Expand All @@ -13,14 +15,16 @@

from collections.abc import Iterable, Mapping
from collections.abc import Set as AbstractSet
from graphlib import TopologicalSorter
from graphlib import CycleError, TopologicalSorter
from typing import Any, TypeGuard

import typing_extensions

from graphqomb.common import Axis, Plane, determine_pauli_axis
from graphqomb.graphstate import BaseGraphState, odd_neighbors

TOPO_ORDER_CYCLE_ERROR_MSG = "No nodes can be measured; possible cyclic dependency or incomplete preparation."


def _is_flow(flowlike: Mapping[int, Any]) -> TypeGuard[Mapping[int, int]]:
r"""Check if the flowlike object is a flow.
Expand Down Expand Up @@ -129,6 +133,60 @@ def check_dag(dag: Mapping[int, Iterable[int]]) -> None:
raise ValueError(msg)


def inverse_dag_from_dag(
dag: Mapping[int, Iterable[int]],
all_nodes: Iterable[int] | None = None,
) -> dict[int, set[int]]:
r"""Build inverse DAG (node -> dependencies) from parent->children DAG.

Parameters
----------
dag : `collections.abc.Mapping`\[`int`, `collections.abc.Iterable`\[`int`\]\]
DAG represented as parent node -> children.
all_nodes : `collections.abc.Iterable`\[`int`\] | `None`, optional
Optional full node set to include isolated nodes.

Returns
-------
`dict`\[`int`, `set`\[`int`\]\]
Inverse DAG represented as node -> dependencies.
"""
nodes = set(all_nodes) if all_nodes is not None else set(dag)
for children in dag.values():
nodes.update(children)

inv_dag: dict[int, set[int]] = {node: set() for node in nodes}
for parent, children in dag.items():
for child in children:
inv_dag[child].add(parent)

return inv_dag


def topo_order_from_inv_dag(inv_dag: Mapping[int, Iterable[int]]) -> list[int]:
r"""Build topological order from an inverse DAG (node -> dependencies).

Parameters
----------
inv_dag : `collections.abc.Mapping`\[`int`, `collections.abc.Iterable`\[`int`\]\]
Inverse DAG where each node maps to the nodes it depends on.

Returns
-------
`list`\[`int`\]
Topological order from dependencies to dependents.

Raises
------
RuntimeError
If topological ordering is not possible due to a cycle.
"""
try:
return list(TopologicalSorter(inv_dag).static_order())
except CycleError as exc:
raise RuntimeError(TOPO_ORDER_CYCLE_ERROR_MSG) from exc


def check_flow(
graph: BaseGraphState,
xflow: Mapping[int, int] | Mapping[int, AbstractSet[int]],
Expand Down
Loading
Loading