Skip to content

Commit

Permalink
XaccQuantum: Fix broken ccx (Toffoli)
Browse files Browse the repository at this point in the history
The current handling of ccx has two problems in HEAD:

1. It is defined with two qubit operands instead of three
2. The implementation in XaccQuantum attempts to create an XACC
   instruction that does not exist

Problem #1 manifests as this assertion tripped inside QIR-EE:

    $ build/bin/qir-xacc -i test/data/bell_ccx.ll --accelerator qpp
    terminate called after throwing an instance of 'qiree::RuntimeError'
      what():  /home/austin/Documents/school/gatech/grad/qsvt/qiree/src/qiree/detail/FunctionChecker.hh:116:
    qir-ee: runtime error: arg_size == irfunc_.arg_size() failed:
        incorrect QIR binding supplied: '__quantum__qis__ccx__body' has 3 arguments but QIR-EE expected 2
    Aborted

Problem #2 pops up when XACC throws the following exception:

    $ build/bin/qir-xacc -i test/data/bell_ccx.ll --accelerator qpp
    terminate called after throwing an instance of 'std::runtime_error'
      what():  Invalid instruction name - CCX
    Aborted

This commit fixes both issues.
  • Loading branch information
ausbin committed Oct 8, 2024
1 parent aef6406 commit 355ac14
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 15 deletions.
6 changes: 4 additions & 2 deletions src/qiree/Executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ bool QIREE_QIS_FUNCTION(read_result, body)(std::uintptr_t arg1)
//---------------------------------------------------------------------------//
// GATES
//---------------------------------------------------------------------------//
void QIREE_QIS_FUNCTION(ccx, body)(std::uintptr_t arg1, std::uintptr_t arg2)
void QIREE_QIS_FUNCTION(ccx, body)(std::uintptr_t arg1,
std::uintptr_t arg2,
std::uintptr_t arg3)
{
return q_interface_->ccx(Qubit{arg1}, Qubit{arg2});
return q_interface_->ccx(Qubit{arg1}, Qubit{arg2}, Qubit{arg3});
}
void QIREE_QIS_FUNCTION(cnot, body)(std::uintptr_t arg1, std::uintptr_t arg2)
{
Expand Down
2 changes: 1 addition & 1 deletion src/qiree/QuantumInterface.hh
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class QuantumInterface
//@{
//! \name Gates

virtual void ccx(Qubit, Qubit) = 0; //!< body
virtual void ccx(Qubit, Qubit, Qubit) = 0; //!< body
virtual void cnot(Qubit, Qubit) = 0; //!< body
virtual void cx(Qubit, Qubit) = 0; //!< body
virtual void cy(Qubit, Qubit) = 0; //!< body
Expand Down
2 changes: 1 addition & 1 deletion src/qiree/QuantumNotImpl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ QState QuantumNotImpl::read_result(Result)
{
QIREE_NOT_IMPLEMENTED("quantum instruction 'read_result.body'");
}
void QuantumNotImpl::ccx(Qubit, Qubit)
void QuantumNotImpl::ccx(Qubit, Qubit, Qubit)
{
QIREE_NOT_IMPLEMENTED("quantum instruction 'ccx.body'");
}
Expand Down
2 changes: 1 addition & 1 deletion src/qiree/QuantumNotImpl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class QuantumNotImpl : virtual public QuantumInterface
//@{
//! \name Gates

void ccx(Qubit, Qubit) override;
void ccx(Qubit, Qubit, Qubit) override;
void cnot(Qubit, Qubit) override;
void cx(Qubit, Qubit) override;
void cy(Qubit, Qubit) override;
Expand Down
73 changes: 69 additions & 4 deletions src/qirxacc/XaccQuantum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <stdexcept>
#include <utility>
#include <xacc/xacc.hpp>
#include <xacc/xacc_service.hpp>

#include "qiree/Assert.hh"

Expand Down Expand Up @@ -152,13 +153,15 @@ QState XaccQuantum::read_result(Result r)
//---------------------------------------------------------------------------//
// QUANTUM INSTRUCTION MAPPING
//---------------------------------------------------------------------------//
void XaccQuantum::ccx(Qubit q1, Qubit q2)
void XaccQuantum::ccx(Qubit q1, Qubit q2, Qubit q3)
{
this->add_instruction("CCX", {q1, q2});
// XACC IR does not have a Toffoli gate
this->add_ctrl_list_instruction("X", {q1, q2}, q3);
}
void XaccQuantum::ccnot(Qubit q1, Qubit q2, Qubit q3)
{
this->add_instruction("CCNOT", {q1, q2, q3});
// XACC IR does not have a Toffoli gate
this->add_ctrl_list_instruction("X", {q1, q2}, q3);
}
void XaccQuantum::cnot(Qubit q1, Qubit q2)
{
Expand Down Expand Up @@ -324,6 +327,22 @@ template<class... Ts>
void XaccQuantum::add_instruction(std::string s,
std::initializer_list<Qubit> qs,
Ts... args)
{
this->add_instruction_to(
cur_circuit_, std::move(s), qs, std::forward<Ts>(args)...);
}

//---------------------------------------------------------------------------//
/*!
* Add an instruction with multiple qubits to a particular XACC
* CompositeInstruction.
*/
template<class... Ts>
void XaccQuantum::add_instruction_to(
std::shared_ptr<xacc::CompositeInstruction> circuit,
std::string s,
std::initializer_list<Qubit> qs,
Ts... args)
{
// Transform opaque qubit types into raw integer indices
std::vector<std::size_t> q_indices(qs.size());
Expand All @@ -338,7 +357,53 @@ void XaccQuantum::add_instruction(std::string s,
std::move(s), q_indices, VecInstr{std::forward<Ts>(args)...});

// Add to current quantum circuit
cur_circuit_->addInstruction(std::move(instr));
circuit->addInstruction(std::move(instr));
}

//---------------------------------------------------------------------------//
/*!
* Add an instruction with the control indices provided.
*/
template<class... Ts>
void XaccQuantum::add_ctrl_indices_instruction(std::string s,
std::vector<int> ctrl_indices,
Qubit q,
Ts... args)
{
std::shared_ptr<xacc::CompositeInstruction> tmp
= provider_->createComposite("tmp");
this->add_instruction_to(tmp, std::move(s), {q}, std::forward<Ts>(args)...);

std::shared_ptr<xacc::CompositeInstruction> cu
= std::static_pointer_cast<xacc::CompositeInstruction>(
xacc::getService<xacc::Instruction>("C-U"));
cu->expand({{"U", tmp}, {"control-idx", ctrl_indices}});

for (int i = 0; i < cu->nInstructions(); i++)
{
cur_circuit_->addInstruction(cu->getInstruction(i));
}
}

//---------------------------------------------------------------------------//
/*!
* Add an instruction with the control indices provided as a list of QIR
* pointers (for convenience).
*/
template<class... Ts>
void XaccQuantum::add_ctrl_list_instruction(
std::string s, std::initializer_list<Qubit> ctrl_list, Qubit q, Ts... args)
{
std::vector<int> ctrl_indices(ctrl_list.size());
std::transform(ctrl_list.begin(),
ctrl_list.end(),
ctrl_indices.begin(),
[this](Qubit q) {
QIREE_EXPECT(q.value < this->num_qubits());
return static_cast<int>(q.value);
});
add_ctrl_indices_instruction(
std::move(s), ctrl_indices, q, std::forward<Ts>(args)...);
}

//---------------------------------------------------------------------------//
Expand Down
25 changes: 24 additions & 1 deletion src/qirxacc/XaccQuantum.hh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class XaccQuantum final : virtual public QuantumNotImpl

//!@{
//! \name Circuit construction
void ccx(Qubit, Qubit) final;
void ccx(Qubit, Qubit, Qubit) final;
void ccnot(Qubit, Qubit, Qubit); // TODO: not in examples or qir runner
void cnot(Qubit, Qubit) final;
void cx(Qubit, Qubit) final;
Expand Down Expand Up @@ -145,6 +145,29 @@ class XaccQuantum final : virtual public QuantumNotImpl
template<class... Ts>
void
add_instruction(std::string s, std::initializer_list<Qubit> qs, Ts... args);

// Add an instruction with multiple qubits to a particular XACC
// CompositeInstruction
template<class... Ts>
void add_instruction_to(std::shared_ptr<xacc::CompositeInstruction> circuit,
std::string s,
std::initializer_list<Qubit> qs,
Ts... args);

// Add an instruction with the control indices provided
template<class... Ts>
void add_ctrl_indices_instruction(std::string s,
std::vector<int> ctrl_indices,
Qubit q,
Ts... args);

// Add an instruction with the control indices provided as a list of QIR
// pointers (for convenience)
template<class... Ts>
void add_ctrl_list_instruction(std::string s,
std::initializer_list<Qubit> ctrl_list,
Qubit q,
Ts... args);
};

//---------------------------------------------------------------------------//
Expand Down
43 changes: 43 additions & 0 deletions test/data/bell_ccx.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
; ModuleID = 'Bell_ccx'
source_filename = "Bell_ccx"

%Qubit = type opaque
%Result = type opaque

define void @main() #0 {
entry:
call void @__quantum__qis__h__body(%Qubit* null)
call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__ccx__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
call void @__quantum__rt__array_record_output(i64 3, i8* null)
call void @__quantum__rt__result_record_output(%Result* null, i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
ret void
}

declare void @__quantum__qis__h__body(%Qubit*)

declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__ccx__body(%Qubit*, %Qubit*, %Qubit*)

declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1

declare void @__quantum__rt__array_record_output(i64, i8*)

declare void @__quantum__rt__result_record_output(%Result*, i8*)

attributes #0 = { "entry_point" "num_required_qubits"="3" "num_required_results"="3" "output_labeling_schema" "qir_profiles"="custom" }
attributes #1 = { "irreversible" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}

21 changes: 21 additions & 0 deletions test/qiree/Executor.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ tear_down
result.commands.str());
}

//---------------------------------------------------------------------------//
TEST_F(ExecutorTest, bell_ccx)
{
auto result = this->run("bell_ccx.ll");
EXPECT_EQ(R"(
set_up(q=3, r=3)
h(Q{0})
TODO: x.body
ccx(Q{0}, Q{1}, Q{2})
mz(Q{0},R{0})
mz(Q{1},R{1})
mz(Q{2},R{2})
array_record_output(3)
result_record_output(R{0})
result_record_output(R{1})
result_record_output(R{2})
tear_down
)",
result.commands.str());
}

//---------------------------------------------------------------------------//
TEST_F(ExecutorTest, rotation)
{
Expand Down
9 changes: 5 additions & 4 deletions test/qiree/QuantumTestImpl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ void QuantumTestImpl::cnot(Qubit q1, Qubit q2)
tr_->commands << "cnot(" << q1 << ", " << q2 << ")\n";
}

void QuantumTestImpl::ccx(Qubit q1, Qubit q2, Qubit q3)
{
tr_->commands << "ccx(" << q1 << ", " << q2 << ", " << q3 << ")\n";
}

//---------------------------------------------------------------------------//
Result QuantumTestImpl::m(Qubit)
{
Expand All @@ -102,10 +107,6 @@ Result QuantumTestImpl::mresetz(Qubit)
tr_->commands << "TODO: mresetz.body\n";
return {};
}
void QuantumTestImpl::ccx(Qubit, Qubit)
{
tr_->commands << "TODO: ccx.body\n";
}
void QuantumTestImpl::cx(Qubit, Qubit)
{
tr_->commands << "TODO: cx.body\n";
Expand Down
2 changes: 1 addition & 1 deletion test/qiree/QuantumTestImpl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class QuantumTestImpl final : public QuantumInterface
Result measure(Array, Array) override;
Result mresetz(Qubit) override;

void ccx(Qubit, Qubit) override;
void ccx(Qubit, Qubit, Qubit) override;
void cx(Qubit, Qubit) override;
void cy(Qubit, Qubit) override;
void cz(Qubit, Qubit) override;
Expand Down

0 comments on commit 355ac14

Please sign in to comment.