-
Notifications
You must be signed in to change notification settings - Fork 47
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
[refactor] new SingleQubitSquash class for squashing #168
Conversation
922b6fe
to
30e82ff
Compare
30e82ff
to
257800a
Compare
The commit history isn't particularly tidy or relevant, so you probably want to review everything in one block. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this refactor adds more lines (865) than it removes (388), I assume the main motivation is that it will save adding new code in the GlobalisePhasedX
pass?
Also nice that we can drop the NoClassicalControlPredicate
in the squashing pass. Are you confident there is enough testing of squashing with classical control?
tket/tests/test_CompilerPass.cpp
Outdated
const Circuit& c = cu.get_circ_ref(); | ||
c.assert_valid(); | ||
REQUIRE(c.n_gates() == 3); | ||
auto cmds = c.get_commands(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the squash_between
method is making my life a lot easier. Although I think most of the code size increase is from comments, classes definition and white space -- the code before was very terse and there definitely isn't a 2x blow-up in the amount of code.
I'll add some testing.
@@ -32,8 +32,6 @@ static bool remove_redundancy( | |||
Circuit &circ, const Vertex &vert, VertexList &bin, | |||
std::set<IVertex> &new_affected_verts, IndexMap &im); | |||
static bool commute_singles_to_front(Circuit &circ); | |||
static bool squash_to_pqp( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you've made a new subdirectory for single-qubit squashing code we should probably also move Transform::squash_1qb_to_tk1()
there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
tket/src/Utils/Expression.cpp
Outdated
return SymEngine::cos(e * SymEngine::pi / 2); | ||
if (is_simpler(e + 2, e)) { | ||
// use cos(x + pi) = -cos(x) | ||
return SymEngine::mul( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised symengine doesn't do this simplification. The machinery for it must be there -- see e.g. https://github.com/symengine/symengine/blob/5c47488c5d1df382d36959b0dad14916dd745f54/symengine/tests/basic/test_functions.cpp#L406
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works if I SymEngine::expand
before the cos
computation. Would you prefer that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in just return SymEngine::cos(Symengine::expand(e * SymEngine::pi / 2));
? That seems better, yes!
tket/src/Utils/Expression.cpp
Outdated
@@ -92,12 +92,30 @@ static Expr cos_pi_by_12_times(double x) { | |||
} | |||
} | |||
|
|||
static bool is_simpler(const Expr& e1, const Expr& e2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry a bit about the performance impact of this. At least we could save one call to expand
(plus json conversion) and one call to dump
by only evaluating them once for e
(rather than repeating in the two calls to this function).
auto it1 = circ.begin(); | ||
auto it2 = gates.cbegin(); | ||
|
||
while (it1 != circ.end() && it2 != gates.end()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we use Gate::operator==
for most of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely!
* | ||
* The squash is made backwards, so that rotations get pushed towards | ||
* the front, see the design choice notes in confluence | ||
* https://cqc.atlassian.net/l/c/17xm5hvp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CQC confluence isn't public so let's not link to it here. Instead summarize the reasons here if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
"Requires two different bases to perform single qubit " | ||
"rotations"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Requires two different bases to perform single qubit " | |
"rotations"); | |
"Requires two different bases to perform single qubit rotations"); |
} | ||
|
||
// squash everything between edges in and out | ||
bool squash_between(const Edge &in, const Edge &out) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of implementation in this header file. Is it worth moving some it out into non-templated "helper" source files, or does it mostly need to be templated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm refactoring it to use polymorphism instead of templating. This makes the abstract interface more explicit and allows me to move all the implementation into a separate cpp
file
bool z_followed_by_measures = true; | ||
for (port_t port = 0; port < kids.size() && z_followed_by_measures; | ||
port++) { | ||
if (circ.get_OpType_from_Vertex(kids[port]) == OpType::Measure) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the test coverage report (which is generally very good), I see a few lines here that are never executed. Can we add one or two more tests to execute lines 298, 310 and 316?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, these lines would only be used if a squasher returned circuits with OpTypes Measure
and noop
, which currently they aren't (and arguably never should).
This part of the code was just copied over from before. I would suggest leaving everything as is for now, but I can add a task to revisit and simplify that remove_redundancy
code, as most of it is probably unnecessary.
Co-authored-by: Alec Edgington <[email protected]>
Running the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to cancel the build because it was stuck running test
after building tket...
8ca3255
to
75d19ad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple of pedantic corrections to the doxygen and one question.
tket/src/Transformations/include/Transformations/SingleQubitSquash.hpp
Outdated
Show resolved
Hide resolved
tket/src/Transformations/include/Transformations/SingleQubitSquash.hpp
Outdated
Show resolved
Hide resolved
const Circuit &sub, const std::vector<Gate_ptr> chain) const { | ||
const unsigned n_gates = sub.n_gates(); | ||
return n_gates < chain.size() || | ||
(n_gates == chain.size() && !is_equal(sub, chain, reversed_)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this ever lead to infinite sequences of squashes where the chain changes each time (cycling between values but staying the same length)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It all depends on the squasher. As long as you have a "normal form" which squashing leaves unchanged (which all well-behaved squasher should have) you'll be fine. In our case this is definitely the case. I can add a line in the docs saying that.
The test failure in the coverage build is puzzling... |
…uash.hpp Co-authored-by: Alec Edgington <[email protected]>
…uash.hpp Co-authored-by: Alec Edgington <[email protected]>
a45bf63
to
ffa6bac
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still failing :-(
This reverts commit c3a1133.
This refactor separates single-qubit squashing into two independent component:
In so doing, it merges most of the implementations of
standard_squash
andpqp_squash
into one, where before both where independent (with a lot of deduplication). This should allow us to add more squashing methods easily in the future.As an added bonus, smart squashing now supports conditional operations!