Skip to content
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

Feature Parse qasm for BlockIR(qasm::String) #8

Merged
merged 6 commits into from
Oct 23, 2023
Merged
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
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)

Check warning on line 11 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L10-L11

Added lines #L10 - L11 were not covered by tests
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))

Check warning on line 37 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L37

Added line #L37 was not covered by tests
@case "x"
Gate(X, qarg_address(i))
@case "h"
Gate(H, qarg_address(i))
@case "s"
Gate(S, qarg_address(i))

Check warning on line 43 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L43

Added line #L43 was not covered by tests
@case "sdg"
Gate(AdjointOperation(S), qarg_address(i))

Check warning on line 45 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L45

Added line #L45 was not covered by tests
@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 _

Check warning on line 58 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L50-L58

Added lines #L50 - L58 were not covered by tests
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")

Check warning on line 76 in ext/YaoHIRExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/YaoHIRExt.jl#L76

Added line #L76 was not covered by tests
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 @@
circuit::Chain
end

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

Check warning on line 118 in src/types.jl

View check run for this annotation

Codecov / codecov/patch

src/types.jl#L117-L118

Added lines #L117 - L118 were not covered by tests
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
Loading