Skip to content

Commit

Permalink
Feature Parse qasm for BlockIR(qasm::String) (#8)
Browse files Browse the repository at this point in the history
* prototype parser and converter for OpenQASM

still a lot of gates to parse,
currently support
- S
- X
- Z
- s
- sDag
- t
- tDag

* use explicit InstrinsicOperation

* remove CompilerPluginTools

* Create YaoHIRExt

* create testsets

* add qasm test

---------

Co-authored-by: liam <[email protected]>
  • Loading branch information
contra-bit and contra-bit authored Oct 23, 2023
1 parent e03925c commit 59a5fd9
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 63 deletions.
11 changes: 9 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ Expronicon = "6b7a57c9-7cc1-4fdf-b7f5-e857abae3636"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
YaoLocations = "66df03fb-d475-48f7-b449-3d9064bf085b"

[weakdeps]
OpenQASM = "a8821629-a4c0-4df7-9e00-12969ff383a7"

[extensions]
YaoHIRExt = ["OpenQASM"]

[compat]
Expronicon = "0.10"
MLStyle = "0.4"
YaoLocations = "0.1"
julia = "1.6"
julia = "1.9"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
OpenQASM = "a8821629-a4c0-4df7-9e00-12969ff383a7"

[targets]
test = ["Test"]
test = ["Test", "OpenQASM"]
80 changes: 80 additions & 0 deletions ext/YaoHIRExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
module YaoHIRExt

using YaoHIR, YaoLocations
using YaoHIR.IntrinsicOperation
using MLStyle
using OpenQASM
using OpenQASM.Types: Instruction, CXGate, Measure, Reset, MainProgram, Include, RegDecl, ASTNode
using Core.Compiler: IRCode

function YaoHIR.BlockIR(ast::MainProgram)
convert_to_blockir(ast::MainProgram)
end
function YaoHIR.BlockIR(qasm::String)
convert_to_blockir(OpenQASM.parse(qasm)::MainProgram)
end

qarg_address(i::Instruction) = Locations(parse(Int, i.qargs[1].address.str) + 1)
qarg_address(i::CXGate) = Locations(parse(Int, i.qarg.address.str) + 1)
#qarg_address(i::CZGate) = Locations(parse(Int, i.qarg.address.str) + 1)
ctrl_address(i::ASTNode) = Locations(parse(Int, i.ctrl.address.str) + 1)


push_prog!(circ::Chain, prog::Any) = prog !== nothing && push!(circ.args, prog)

function convert_to_blockir(ast::MainProgram)
qubits = sum([parse(Int, m.size.str) for m in ast.prog if m isa RegDecl && m.type.str == "qreg"])
ir = IRCode()
chain = Chain()
[push_prog!(chain, prog_to_gate(prog)) for prog in ast.prog]
BlockIR(ir, qubits, chain)
end


function instruction_to_gate(i::Instruction)
@switch i.name begin
@case "z"
Gate(Z, qarg_address(i))
@case "x"
Gate(X, qarg_address(i))
@case "h"
Gate(H, qarg_address(i))
@case "s"
Gate(S, qarg_address(i))
@case "sdg"
Gate(AdjointOperation(S), qarg_address(i))
@case "t"
Gate(S, qarg_address(i))
@case "tdg"
Gate(AdjointOperation(T), qarg_address(i))
@case "rx"
error("Gate $i not yet implemented")
@case "rx"
error("Gate $i not yet implemented")
@case "shift"
error("Gate $i not yet implemented")
@case "id"
nothing
@case _
error("Gate $i not supported")
end
end

function prog_to_gate(a::Any)
@match a begin
i::Include => nothing
r::RegDecl => nothing
inst::Instruction => instruction_to_gate(inst)
cx::CXGate => Ctrl(Gate(X,
Locations(qarg_address(cx))),
CtrlLocations(ctrl_address(cx)))

# cz::CZGate => Ctrl(Gate(Z,
# Locations(qarg_address(cz))),
# CtrlLocations(ctrl_address(cz)))
m::Measure => nothing
r::Reset => error("only unitaries are supported, please use the function reconstruct_unitaries from the package QuantumCircuitEquivalence.jl")
end
end

end
10 changes: 5 additions & 5 deletions src/YaoHIR.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module YaoHIR

export GenericRoutine, Routine,
IntrinsicRoutine,
Operation,
AdjointOperation,
Chain, Gate, Ctrl,
BlockIR
IntrinsicRoutine,
Operation,
AdjointOperation,
Chain, Gate, Ctrl,
BlockIR

using MLStyle
using Expronicon
Expand Down
4 changes: 4 additions & 0 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ struct BlockIR
circuit::Chain
end

function BlockIR(_::Any)
error("it is required to load OpenQASM for conversion .qasm. Run 'using OpenQASM'")
end

@as_record Chain
@as_record Gate
@as_record Ctrl
Expand Down
53 changes: 53 additions & 0 deletions test/hir.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

@testset "types" begin
@test YaoHIR.routine_name(TestIntrinsic.X) == :X
@test YaoHIR.routine_name(TestIntrinsic.R(1.0)) == :R
@test TestIntrinsic.R(1.0).theta == 1.0

display(X)
display(Rx(1.0))
display(YaoHIR.Operation(X, 2.0))

circ = Chain(
Gate(X, Locations(1)),
Core.SSAValue(1),
Ctrl(Gate(Core.SSAValue(1), Locations(3)), CtrlLocations(2))
)

print(circ)

@test YaoHIR.leaves(circ) == [Gate(X, Locations(1)),
Core.SSAValue(1),
Ctrl(Gate(Core.SSAValue(1), Locations(3)), CtrlLocations(2))
]

end


@testset "test match" begin
gate = Gate(X, Locations(2))

@match gate begin
Gate(op, locs) => begin
@test op == X
@test locs == Locations(2)
end
end

ctrl = Ctrl(Gate(X, Locations(2)), CtrlLocations(3))

@match ctrl begin
Ctrl(Gate(op, locs), ctrl) => begin
@test op == X
@test locs == Locations(2)
@test ctrl == CtrlLocations(3)
end
end
end

@testset "isequal" begin
circuit1 = Chain(Gate(H, Locations((1, ))), Gate(H, Locations((1, ))))
circuit2 = Chain(Gate(H, Locations((1, ))), Gate(H, Locations((1, ))))
@test circuit1 == circuit2
end

16 changes: 16 additions & 0 deletions test/instrinsic.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module TestIntrinsic
using YaoHIR: @intrinsic

@intrinsic X
@intrinsic R(theta::T) where {T <: Real}
@intrinsic SWAP

end

@testset "instrinic" begin

@test YaoHIR.routine_name(TestIntrinsic.X) == :X
@test YaoHIR.routine_name(TestIntrinsic.R(1.0)) == :R
@test TestIntrinsic.R(1.0).theta == 1.0

end
167 changes: 167 additions & 0 deletions test/qasm.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using YaoHIR
using YaoHIR.IntrinsicOperation
using OpenQASM

@testset "convert qasm" begin

bir = BlockIR("""
OPENQASM 2.0;
include "qelib1.inc";
qreg q0[3];
creg c0[2];
h q0[0];
h q0[1];
x q0[2];
h q0[2];
CX q0[0], q0[2];
h q0[0];
measure q0[0] -> c0[0];
CX q0[1], q0[2];
h q0[1];
measure q0[1] -> c0[1];
""")

@testset "correct parsing" begin
bir !== nothing
end

chain = Chain(
Gate(H, Locations(1)),
Gate(H, Locations(2)),
Gate(X, Locations(3)),
Gate(H, Locations(3)),
Ctrl(Gate(X, Locations(3)), CtrlLocations(1)),
Gate(H, Locations(1)),
Ctrl(Gate(X, Locations(3)), CtrlLocations(2)),
Gate(H, Locations(2))
)

@testset "conversion" begin
@test chain == bir.circuit
end


@testset "parse DJ-NAND" begin
bv = BlockIR("""
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[2];
h q[0];
h q[1];
x q[2];
h q[2];
x q[2];
h q[2];
cx q[1],q[2];
tdg q[2];
cx q[0],q[2];
t q[2];
cx q[1],q[2];
t q[1];
tdg q[2];
cx q[0],q[2];
cx q[0],q[1];
t q[0];
tdg q[1];
cx q[0],q[1];
h q[0];
h q[1];
t q[2];
h q[2];
measure q[0] -> c[0];
measure q[1] -> c[1];
""")


bv_re = BlockIR("""
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c1[1];
creg c2[1];
h q[1];
t q[1];
x q[2];
h q[2];
x q[2];
h q[2];
t q[2];
CX q[1], q[2];
tdg q[2];
CX q[1], q[2];
h q[1];
h q[2];
h q[2];
t q[2];
h q[0];
t q[0];
CX q[0], q[2];
tdg q[2];
CX q[0], q[2];
CX q[1], q[0];
tdg q[0];
tdg q[2];
CX q[0], q[2];
t q[2];
CX q[0], q[2];
CX q[1], q[0];
h q[0];
h q[2];
measure q[0] -> c2[0];
measure q[1] -> c1[0];""")

@testset "correct parsing" begin
@test bv !== nothing
end

@testset "convert into BlockIR" begin
@test bv_re !== nothing

end

end

@testset "dj 3" begin
dj3 = BlockIR("""
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[2];
h q[0];
h q[1];
x q[2];
x q[0];
x q[1];
h q[2];
cx q[0],q[2];
x q[0];
cx q[1],q[2];
h q[0];
x q[1];
h q[1];
""")

chain = Chain(Gate(H, Locations(1)),
Gate(H, Locations(2)),
Gate(X, Locations(3)),
Gate(X, Locations(1)),
Gate(X, Locations(2)),
Gate(H, Locations(3)),
Ctrl(Gate(X, Locations(3)),
CtrlLocations(1)),
Gate(X, Locations(1)),
Ctrl(Gate(X, Locations(3)),
CtrlLocations(2)),
Gate(H, Locations(1)),
Gate(X, Locations(2)),
Gate(H, Locations(2)))

@test dj3.circuit == chain
# FIXME should an empty IR print '1 ─ return nothing' ?
# print(dj3)

end

end
Loading

0 comments on commit 59a5fd9

Please sign in to comment.