Skip to content

Commit

Permalink
Edge-disjoint paths in the wave pipeline (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
tylerrleblond authored Oct 22, 2024
1 parent 01ca53d commit c0a02d8
Show file tree
Hide file tree
Showing 75 changed files with 32,093 additions and 8,411 deletions.
51 changes: 34 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

![](https://user-images.githubusercontent.com/36427091/193476068-eddfea28-3d91-4398-8de4-3a55bb43faa7.gif)

[Publication link for original compiler release](https://quantum-journal.org/papers/q-2024-05-22-1354/)
[Publication link for upgraded compiler and its usage in resource estimation](https://dl.acm.org/doi/abs/10.1145/3689826)

Home of a set of fast tools for compiling lattice surgery instructions. Part of the [Lattice Surgery Compiler](https://github.com/latticesurgery-com/lattice-surgery-compiler) family. The `liblsqecc` library contains the functionality used by the `lsqecc_slicer` executable. We are working on exposing its functionality as a Python API in the [Lattice Surgery Compiler](https://github.com/latticesurgery-com/lattice-surgery-compiler) package.

## Build
Expand Down Expand Up @@ -52,21 +55,25 @@ Options:
-f, --output-format Requires -o, STDOUT output format: progress, noprogress, machine, stats
-t, --timeout Set a timeout in seconds after which stop producing slices
-r, --router Set a router: graph_search (default), graph_search_cached
-P, --pipeline pipeline mode: stream (default), dag, wave
-g, --graph-search Set a graph search provider: djikstra (default), astar, boost (not always available) [ignored by -P wave pipeline, which uses astar]
-P, --pipeline pipeline mode: stream (default), wave, edpc, dag (deprecated)
-g, --graph-search Set a graph search provider: djikstra (default), astar, boost (not always available)
--graceful If there is an error when slicing, print the error and terminate
--printlli Output LLI instead of JSONs. options: before (default), sliced (prints lli on the same slice separated by semicolons)
--printdag Prints a dependancy dag of the circuit. Modes: input (default), processedlli
--printdag Prints a dependency dag of the circuit. Modes: input (default), processedlli
--noslices Do the slicing but don't write the slices out
--cnotcorrections Add Xs and Zs to correct the the negative outcomes: never (default), always
--layoutgenerator, -L Automatically generates a layout for the given number of qubits. Incompatible with -l. Options:
- compact (default): Uses Litinski's Game of Surace Code compact layout (https://arxiv.org/abs/1808.02892)
- compact_no_clogging: same as compact, but fewer cells for ancillas and magic state queues
- edpc: Uses a layout specified in the EDPC paper by Beverland et. al. (https://arxiv.org/abs/2110.11493)
- edpc: Uses a family of layouts based upon the one specified in the EDPC paper by Beverland et. al. (https://arxiv.org/abs/2110.11493)
--numlanes Only compatible with -L edpc. Configures number of free lanes for routing.
--condensed Only compatible with -L edpc. Packs logical qubits more compactly.
--explicitfactories Only compatible with -L edpc. Explicitly specifies factories but clogs easily (otherwise, uses tiles reserved for magic state re-spawn).
--nostagger Turns off staggered distillation block timing
--disttime Set the distillation time (default 10)
--local Compile gates using a local lattice surgery instruction set
-h, --help Shows this page
--local Compile gates into a pair-wise local lattice surgery instruction set
--notwists Compile S gates using the catalytic teleportation circuit from Fowler, 2012 instead of using the twist-based Y state initialization and teleportation from Gidney, 2024
-h, --help Shows this page
```
### OpenQASMmin: a OpenQASM dialect (Experimental)

Expand Down Expand Up @@ -113,27 +120,37 @@ However due to the Haskell platform's own portability challenges and some low le
To generate results according to the compilation scheme written about in [our recent paper](https://arxiv.org/abs/2311.10686), use the following options:

``` shell
lsqecc_slicer -q -i {qasm_filename} -L edpc --disttime 1 --nostagger --local -P wave --printlli sliced -o {lli_filename} -f stats > {stats_filename}
lsqecc_slicer -q -i {qasm_filename} -L edpc --disttime 1 --nostagger --notwists --local -P wave --printlli sliced -o {lli_filename} -f stats > {stats_filename}
```

Results in that paper were generated using [PR #106](https://github.com/latticesurgery-com/liblsqecc/pull/106), and should be reproducible using the current release.

# Contributors

Liblsqecc was primarily developed at Aalto University by [George Watkins](https://github.com/gwwatkin) under [Alexandru Paler](https://github.com/alexandrupaler)'s supervision, and is now maintained by George Watkins.

A special thanks to [Tyler LeBlond (Oak Ridge National Laboratory)](https://github.com/tylerrleblond) and [Christopher Dean (Dalhousie University)](https://github.com/christopherjdean) for adding the EDPC layout family, the local compilation layer, the wave pipeline, and other contributions according to the compilation strategy outlined in [their recent paper](https://arxiv.org/abs/2311.10686).
Liblsqecc was originally developed at Aalto University by [George Watkins](https://github.com/gwwatkin) under [Alexandru Paler](https://github.com/alexandrupaler)'s supervision and was later upgraded by [Tyler LeBlond (Oak Ridge National Laboratory)](https://github.com/tylerrleblond) and [Christopher Dean (Dalhousie University)](https://github.com/christopherjdean) in collaboration with [George Watkins](https://github.com/gwwatkin). The compiler is currently maintained primarily by [Tyler LeBlond](https://github.com/tylerrleblond) and ongoing development is co-led with [Alexandru Paler](https://github.com/alexandrupaler).

[Alex Nguyen](https://github.com/alexnguyenn) maintains the NPM package and associated infrastructure.

# Citing
The original release of the compiler should be cited as follows:
```
@article{watkins2024high,
title={A high performance compiler for very large scale surface code computations},
author={Watkins, George and Nguyen, Hoang Minh and Watkins, Keelan and Pearce, Steven and Lau, Hoi-Kwan and Paler, Alexandru},
journal={Quantum},
volume={8},
pages={1354},
year={2024},
publisher={Verein zur F{\"o}rderung des Open Access Publizierens in den Quantenwissenschaften}
}
```

Please cite as follows:
The upgraded compiler and its usage in resource estimation should be cited as follows:
```
@article{watkins2023high,
title={A High Performance Compiler for Very Large Scale Surface Code Computations},
author={Watkins, George and Nguyen, Hoang Minh and Seshadri, Varun and Watkins, Keelan and Pearce, Steven and Lau, Hoi-Kwan and Paler, Alexandru},
journal={arXiv preprint arXiv:2302.02459},
year={2023}
@article{leblond2023realistic,
title={Realistic Cost to Execute Practical Quantum Circuits using Direct Clifford+ T Lattice Surgery Compilation},
author={LeBlond, Tyler and Dean, Christopher and Watkins, George and Bennink, Ryan},
journal={ACM Transactions on Quantum Computing},
year={2023},
publisher={ACM New York, NY}
}
```
3 changes: 2 additions & 1 deletion include/lsqecc/layout/graph_search/custom_graph_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ std::optional<RoutingRegion> graph_search_route_ancilla(
PauliOperator source_op,
PatchId target,
PauliOperator target_op,
Heuristic heuristic
Heuristic heuristic,
bool EDPC
);

}
Expand Down
17 changes: 17 additions & 0 deletions include/lsqecc/layout/router.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct Router {
) const = 0;

virtual void set_graph_search_provider(GraphSearchProvider graph_search_provider) = 0;
virtual void set_EDPC() = 0;
virtual bool get_EDPC() = 0;

virtual ~Router(){};
};
Expand All @@ -45,8 +47,20 @@ struct CustomDPRouter : public Router
graph_search_provider_ = graph_search_provider;
};

void set_EDPC() override {
if (graph_search_provider_ == GraphSearchProvider::Boost) {
throw std::logic_error("EDPC not implemented for Boost.");
}
else {
EDPC = 1;
}
}

bool get_EDPC() override {return EDPC;}

private:
GraphSearchProvider graph_search_provider_ = GraphSearchProvider::Djikstra;
bool EDPC = 0;

};

Expand All @@ -72,6 +86,9 @@ struct CachedRouter : public Router
router_impl_.set_graph_search_provider(graph_search_provider);
};

void set_EDPC() override {throw std::logic_error("EDPC not implemented for cached router.");}
bool get_EDPC() override {return 0;}

struct PathIdentifier {
Cell source_cell;
PauliOperator source_op;
Expand Down
6 changes: 4 additions & 2 deletions include/lsqecc/ls_instructions/ls_instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ struct BellBasedCNOT {
PatchId side1;
PatchId side2;

std::optional<std::vector<LocalInstruction::LocalLSInstruction>> local_instructions;
std::optional<std::pair<unsigned int, unsigned int>> counter;
std::optional<RoutingRegion> route;
std::optional<std::vector<std::pair<unsigned int, unsigned int>>> counter_pairs;
std::optional<std::vector<std::vector<LocalInstruction::LocalLSInstruction>>> local_instruction_sets;
std::optional<size_t> current_phase;

bool operator==(const BellBasedCNOT&) const = default;
};
Expand Down
4 changes: 2 additions & 2 deletions include/lsqecc/patches/dense_patch_computation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
namespace lsqecc {

enum class PipelineMode {
Stream, Dag, Wave
Stream, Dag, Wave, EDPC
};

using DenseSliceVisitor = std::function<void(const DenseSlice& slice)>;
Expand All @@ -44,7 +44,7 @@ DensePatchComputationResult run_through_dense_slices(
bool local_instructions,
bool allow_twists,
const Layout& layout,
Router& router,
std::unique_ptr<Router> router,
std::optional<std::chrono::seconds> timeout,
DenseSliceVisitor slice_visitor,
LSInstructionVisitor instruction_visitor,
Expand Down
13 changes: 13 additions & 0 deletions include/lsqecc/patches/dense_slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ struct DenseSlice : public Slice
DistillationTimeMap time_to_next_magic_state_by_distillation_region;
std::reference_wrapper<const Layout> layout;
unsigned int predistilled_ystates_available = 0;
std::set<Cell> EDPC_crossing_vertices;
// std::vector<std::pair<Cell, Cell>> marked_rough_boundaries_EDPC;
// std::vector<std::pair<Cell, Cell>> marked_smooth_boundaries_EDPC;
std::vector<std::reference_wrapper<Boundary>> marked_rough_boundaries_EDPC;
std::vector<std::reference_wrapper<Boundary>> marked_smooth_boundaries_EDPC;


explicit DenseSlice(const Layout& layout);
DenseSlice(const Layout& layout, const tsl::ordered_set<PatchId>& core_qubit_ids);
Expand All @@ -50,6 +56,7 @@ struct DenseSlice : public Slice
std::reference_wrapper<Boundary> get_boundary_between_or_fail(const Cell& target, const Cell& neighbour);
std::optional<std::reference_wrapper<const Boundary>> get_boundary_between(const Cell& target, const Cell& neighbour) const;
bool have_boundary_of_type_with(const Cell& target, const Cell& neighbour, PauliOperator op) const override;
bool is_boundary_reserved(const Cell& target, const Cell& neighbour) const override;

// Return a cell of the placed patch
Cell place_single_cell_sparse_patch(const SparsePatch& sparse_patch, bool distillation);
Expand All @@ -58,10 +65,16 @@ struct DenseSlice : public Slice
void delete_patch_by_id(PatchId id);

bool is_cell_free(const Cell& cell) const override;
bool is_cell_free_or_activity(const Cell& cell, std::vector<PatchActivity> activities) const override;

std::optional<Cell> get_directional_neighbor_within_slice(const Cell& cell, CellDirection dir) const override;
std::vector<Cell> get_neigbours_within_slice(const Cell& cell) const override;

SurfaceCodeTimestep time_to_next_magic_state(size_t distillation_region_id) const override;

void flip_crossing_chain(const Cell& crossing_cell, CellDirection dir);

BoundaryType mark_boundaries_for_crossing_cell(DensePatch& dp, const SingleCellOccupiedByPatch& p, const Cell& prev);
};

}
Expand Down
17 changes: 16 additions & 1 deletion include/lsqecc/patches/patches.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,19 @@ enum class BoundaryType : uint8_t {
Connected, // Used for multi patch
Rough,
Smooth,
Reserved_Label1, // Used by EDPC to denote the two VDP path sets of one EDP set
Reserved_Label2,
};

enum class CellDirection {
top, bottom, left, right
};

CellDirection operator!(CellDirection dir);

BoundaryType operator!(BoundaryType bt);

std::ostream& operator<<(std::ostream& os, BoundaryType bt);

BoundaryType boundary_for_operator(PauliOperator op);

Expand All @@ -30,6 +41,7 @@ struct Cell {

std::vector<Cell> get_neigbours() const;
std::vector<Cell> get_neigbours_within_bounding_box_inclusive(const Cell& origin, const Cell& furthest_cell) const;
std::optional<Cell> get_directional_neighbor(const Cell& origin, const Cell& furthest_cell, CellDirection dir) const;

template<class IntType>
static Cell from_ints(IntType _row, IntType _col)
Expand Down Expand Up @@ -63,7 +75,9 @@ enum class PatchActivity : uint8_t
Distillation,
Dead,
MultiPatchMeasurement,
Rotation
Rotation,
EDPC,
Reserved
};


Expand Down Expand Up @@ -94,6 +108,7 @@ struct SingleCellOccupiedByPatch : public CellBoundaries {
Cell cell;

std::optional<Boundary> get_boundary_with(const Cell& neighbour) const;
std::optional<Boundary*> get_boundary_reference_with(const Cell& neighbour);
bool have_boundary_of_type_with(PauliOperator op, const Cell& neighbour) const;
std::optional<std::reference_wrapper<Boundary>> get_mut_boundary_with(const Cell& neighbour);

Expand Down
3 changes: 3 additions & 0 deletions include/lsqecc/patches/slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ struct Slice
virtual bool has_patch(PatchId id) const = 0;
virtual std::optional<Cell> get_cell_by_id(const PatchId id) const = 0;
virtual bool is_cell_free(const Cell& cell) const = 0;
virtual bool is_cell_free_or_activity(const Cell& cell, std::vector<PatchActivity> activities) const = 0;
virtual std::optional<Cell> get_directional_neighbor_within_slice(const Cell& cell, CellDirection dir) const = 0;
virtual std::vector<Cell> get_neigbours_within_slice(const Cell& cell) const = 0;
virtual bool have_boundary_of_type_with(const Cell& target, const Cell& neighbour, PauliOperator op) const = 0;
virtual bool is_boundary_reserved(const Cell& target, const Cell& neighbour) const = 0;
virtual SurfaceCodeTimestep time_to_next_magic_state(size_t distillation_region_id) const = 0;

virtual ~Slice(){};
Expand Down
3 changes: 3 additions & 0 deletions include/lsqecc/patches/sparse_slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ struct SparseSlice : public Slice{
std::optional<std::reference_wrapper<const SparsePatch>> get_magic_state_on_cell(const Cell& cell) const;
std::optional<std::reference_wrapper<const SparsePatch>> get_any_patch_on_cell(const Cell& cell) const;
bool is_cell_free(const Cell& cell) const override;
bool is_cell_free_or_activity(const Cell& cell, std::vector<PatchActivity> activities) const override;
std::optional<Cell> get_directional_neighbor_within_slice(const Cell& cell, CellDirection dir) const override;
std::vector<Cell> get_neigbours_within_slice(const Cell& cell) const override;
bool have_boundary_of_type_with(const Cell& target, const Cell& neighbour, PauliOperator op) const override;
bool is_boundary_reserved(const Cell& target, const Cell& neighbour) const override;

SurfaceCodeTimestep time_to_next_magic_state(size_t distillation_region_id) const override;

Expand Down
17 changes: 12 additions & 5 deletions include/lsqecc/scheduler/wave_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class WaveScheduler
{
public:

WaveScheduler(LSInstructionStream&& stream, bool local_instructions, bool allow_twists, const Layout& layout);
WaveScheduler(LSInstructionStream&& stream, bool local_instructions, bool allow_twists, const Layout& layout, std::unique_ptr<Router> router, PipelineMode pipeline_mode);

bool done() const { return current_wave_.proximate_heads_.empty() && current_wave_.heads.empty(); }
WaveStats schedule_wave(DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res);
Expand All @@ -44,27 +44,34 @@ class WaveScheduler
{
std::vector<InstructionID> heads;
std::vector<InstructionID> proximate_heads_;
std::vector<InstructionID> deferred_to_end;

void clear()
{
heads.clear();
proximate_heads_.clear();
deferred_to_end.clear();
}

std::vector<InstructionID> get_deferred() const
{
return deferred_to_end;
}

size_t size() const { return heads.size() + proximate_heads_.size(); }
};

// returns number of instruction_ids that were applied
size_t schedule_instructions(const std::vector<InstructionID>& instruction_ids, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res, bool proximate);
void schedule_dependent_instructions(InstructionID instruction_id, const std::vector<LSInstruction>& followup_instructions, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res);
size_t schedule_instructions(const std::vector<InstructionID>& instruction_ids, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res, bool proximate, bool deferred);
void schedule_dependent_instructions(InstructionID instruction_id, const std::vector<LSInstruction>& followup_instructions, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res, bool proximate);

bool is_immediate(const LSInstruction& instruction);
bool try_schedule_immediately(InstructionID instruction_id, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res);
bool try_schedule_immediately(InstructionID instruction_id, DenseSlice& slice, LSInstructionVisitor instruction_visitor, DensePatchComputationResult& res, bool proximate);

bool local_instructions_;
bool allow_twists_;
const Layout& layout_;
CustomDPRouter router_;
std::unique_ptr<Router> router_;

std::vector<InstructionRecord> records_;
std::vector<uint8_t> dependency_counts_;
Expand Down
12 changes: 6 additions & 6 deletions regression_tests/cases/bellbased/3.spec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c0a02d8

Please sign in to comment.