QuantumBFS / YaoBlocks.jl

Standard basic quantum circuit simulator building blocks. (archived, for it is moved to Yao.jl)
Apache License 2.0
26 stars 11 forks source link

`ControlBlock` should be primitive #4

Open GiggleLiu opened 5 years ago

GiggleLiu commented 5 years ago
Roger-luo commented 5 years ago

The definition of composition is Block constructed by other blocks. The reason why RotationGate is primitive is because the usually we only use XYZ block and use that as a mark, that's why it's primitive. But it's true, one can also rotate on a parametrized block, so making RotationGate a composite gate is more correct.

On the other hand, if control become primitive, there'll be a large influence on printing, cache and block tree iteration.

Note: the concept composition doesn't have anything to do with its methods. It's only about type.

GiggleLiu commented 5 years ago
  1. we can also use SWAP and CNOT (any Hermitian, Reflexive operator) inside a RotationGate.
  2. when X, Y and Z gate used in controlled block and rotation block, they are not actually applied. In fact, for rotation gate, it is incorrect to call its sub-block as a gate, it is a generator.

The definition of composition is Block constructed by other blocks.

constructed by is not accurate. Let's say, apply! of sub-blocks are called, or effectively called. At least this is physically well defined.

On the other hand, if control become primitive, there'll be a large influence on printing, cache and block tree iteration.

It should be special

Roger-luo commented 5 years ago

we can also use SWAP and CNOT (any Hermitian, Reflexive operator) inside a RotationGate.

This is also the reason to make it composite, see what I replied above.

constructed by is not accurate. Let's say, apply! of sub-blocks are called, or effectively called. At least this is physically well defined.

The tiny type system inside Yao is based on some basic type theory definition. This is already accurate enough: https://en.wikipedia.org/wiki/Composite_data_type

The type system inside Yao for quantum operators, is just a mirror of Julia type system, and should not be different (or it will cause the library become non-idiomatic).

The reason why there's nothing to do with a specific method is because we don't want to mangle type with methods, type is a separated concept. This is straight forward, well known and easy to understand.

It should be special

I don't see any benefits to make this special. Making anything special will result in inconsistency, which is the original reason you mentioned in this issue. So it doesn't make any difference.

If we make this special by re-writing a large amount of code to only make gate counting easier, I don't think it worth it, since you only need to define a single line to make gate counting correct:

ngate(::ControlBlock) = 1 # or whatever this should be

PS. the number of gates should depend on the structure of control block, if we are talking about hardware related gate counting.

Roger-luo commented 5 years ago

The only two primitive blocks that remains questionable are RotationGate and TimeEvolution, but the reason why they are primitive is also simple:

and as for apply!, the general control block (note this block is general, which means it should be able to control an arbitrary block) should use its subblock's apply! instead of its matrix when its subblock is too large (we do this in some old version of Yao, I can't remember).

In fact, I'm specializing those apply!s for specific gates to their own instruction. And would prefer to make control's apply! make use of other blocks' apply in the future (or it won't be possible to calculate a large controlled gate, which is necessary to my old project about algorithmic cooling technique: https://arxiv.org/abs/1208.2256)

GiggleLiu commented 5 years ago

re-writing a large amount of code

I don't think so, like RotationGate, the file is not much longer than ControlBlock.

to only make gate counting easier

The major difference is the subblocks interface, allowing access to sub-blocks may have the following trouble.

Roger-luo commented 5 years ago

Gate Counting and Timing a circuit should be handled as special cases.

I think is straight forward, and remember control gate has type parameters, you can/should dispatch it according to what's in it.

Make autodiff harder to implement, unlike Rz(theta) in other composite blocks, the gradient of C-Rz(theta) can not be obtained using the formula in this paper. Making Controlled Blocks

similar as above, you can just dispatch based on the type. And this could be why original autodiff is hard to support this and require a refactor against Flux.

Potential confusion in gate filtering. When people are filtering gates, is it expected to filter out an X gate out of a CNOT gate? CNOT is already an elementary gate, from both programming realization (apply! function of subblocks not called) and experimental realization (controlled-U is not composed of U).

If the controlled block is a parameterized block, e.g control(Rx(theta)), filter out a Rx(theta) is expected. If you want to filter out control(X) together, you should use our new postwalk / prewalk.

The only composite block that bind to instruct directly?

Again, composition is not about what methods it has.

GiggleLiu commented 5 years ago

I would also suggest to make Daggered as a subtype of PrimitiveBlock. It also changes the behavior of apply!.

Roger-luo commented 5 years ago

Daggered will be part of the symbolic computation (which are all special marks on block and are composite blocks), or it would be hard to optimize things like the following:

dag(X) * Y * dag(Z) * X * dag(dag(Z) * dag(Y))
GiggleLiu commented 5 years ago

The example is not proper, dag is a function that can propagate through composite gates.

Daggered is a type.