Skip to content

Commit

Permalink
Upgrade mapper/router to new IR
Browse files Browse the repository at this point in the history
- New IR in place of old IR
- New DDG is used in place of old scheduler
- Various code improvements (e.g. return result instead of modify
  reference parameter)
  • Loading branch information
pablolh committed Dec 7, 2022
1 parent a73f829 commit 62efe42
Show file tree
Hide file tree
Showing 44 changed files with 1,302 additions and 3,261 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ add_library(ql
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/sch/scheduler.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/map/expression_mapper.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/map/qubit_mapping.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/map/reference_updater.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/dec/unitary.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/dec/rules.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ql/com/dec/structure.cc"
Expand Down
6 changes: 3 additions & 3 deletions include/ql/com/ddg/build.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class EventGatherer {
/**
* Reference to the root of the IR.
*/
ir::Ref ir;
ir::PlatformRef platform;

/**
* The actual event list.
Expand Down Expand Up @@ -49,7 +49,7 @@ class EventGatherer {
/**
* Constructs an object reference gatherer.
*/
explicit EventGatherer(const ir::Ref &ir);
explicit EventGatherer(const ir::PlatformRef &p);

/**
* Returns the contained list of object accesses.
Expand Down Expand Up @@ -116,7 +116,7 @@ class EventGatherer {
* node in the final schedule, and such that the sign indicates the direction
*/
void build(
const ir::Ref &ir,
const ir::PlatformRef &platform,
const ir::BlockBaseRef &block,
utils::Bool commute_multi_qubit = true,
utils::Bool commute_single_qubit = true
Expand Down
2 changes: 2 additions & 0 deletions include/ql/com/ddg/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ void clear(const ir::BlockBaseRef &block);
*/
void reverse(const ir::BlockBaseRef &block);

void add_remaining(const ir::BlockBaseRef &block);

} // namespace ddg
} // namespace com
} // namespace ql
6 changes: 6 additions & 0 deletions include/ql/com/ddg/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,12 @@ struct Graph {

};

struct Remaining {
utils::UInt remaining = 0;

Remaining(utils::UInt r) : remaining(r) {};
};

} // namespace ddg
} // namespace com
} // namespace ql
33 changes: 33 additions & 0 deletions include/ql/com/map/reference_updater.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "ql/ir/ir.h"

namespace ql {
namespace com {
namespace map {

class ReferenceUpdater : public ir::RecursiveVisitor {
public:
using Callback = std::function<void(utils::UInt)>;

ReferenceUpdater(ir::PlatformRef p, const utils::Vec<utils::UInt> &m,
Callback c = {}) : platform(p), mapping(m), callback(c) {}

void visit_node(ir::Node &node) override {};

void visit_reference(ir::Reference &ref) override;

// Gate operands may be virtual qubits, but in the instruction type it's always real qubit indices.
void visit_instruction_type(ir::InstructionType &t) override {};

private:
ir::PlatformRef platform;
const utils::Vec<utils::UInt> &mapping;
Callback callback{};
};

void mapInstruction(const ir::PlatformRef &platform, const utils::Vec<utils::UInt> &mapping, const ir::CustomInstructionRef &instr, ReferenceUpdater::Callback callback = {});

void mapProgram(const ir::PlatformRef &platform, const utils::Vec<utils::UInt> &mapping, const ir::ProgramRef &program);

}
}
}
20 changes: 2 additions & 18 deletions include/ql/ir/compat/gate.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "ql/utils/json.h"
#include "ql/utils/misc.h"
#include "ql/utils/tree.h"
#include "ql/ir/swap_parameters.h"

namespace ql {
namespace ir {
Expand Down Expand Up @@ -70,23 +71,6 @@ std::ostream &operator<<(std::ostream &os, ConditionType condition_type);

const utils::UInt MAX_CYCLE = utils::MAX;

struct SwapParamaters {
utils::Bool part_of_swap = false;
// at the end of the swap r0 stores v0 and r1 stores v1
utils::Int r0 = -1;
utils::Int r1 = -1;
utils::Int v0 = -1;
utils::Int v1 = -1;

// default constructor
SwapParamaters() {}

// initializer list
SwapParamaters(utils::Bool _part_of_swap, utils::Int _r0, utils::Int _r1, utils::Int _v0, utils::Int _v1)
: part_of_swap(_part_of_swap), r0(_r0), r1(_r1), v0(_v0), v1(_v1)
{}
};

/**
* gate interface
*/
Expand All @@ -98,7 +82,7 @@ class Gate : public utils::Node {
utils::Vec<utils::UInt> breg_operands; // bit operands e.g. assigned to by measure; cond_operands are separate
utils::Vec<utils::UInt> cond_operands; // 0, 1 or 2 bit operands of condition
ConditionType condition = ConditionType::ALWAYS; // defines condition and by that number of bit operands of condition
SwapParamaters swap_params; // if the gate is part of a swap/move, this will contain the real and virtual qubits involved
SwapParameters swap_params; // if the gate is part of a swap/move, this will contain the real and virtual qubits involved
utils::Int int_operand = 0; // FIXME: move to class 'classical'
utils::UInt duration = 0;
utils::Real angle = 0.0; // for arbitrary rotations
Expand Down
5 changes: 5 additions & 0 deletions include/ql/ir/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ using StatementRef = utils::One<Statement>;
*/
using InstructionRef = utils::One<Instruction>;

/**
* Reference to a custom instruction.
*/
using CustomInstructionRef = utils::One<CustomInstruction>;

/**
* Link to a (custom) instruction type.
*/
Expand Down
143 changes: 136 additions & 7 deletions include/ql/ir/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ InstructionTypeLink add_instruction_type(
* created, an empty link is returned.
*/
InstructionTypeLink find_instruction_type(
const Ref &ir,
const PlatformRef &platform,
const utils::Str &name,
const utils::Vec<DataTypeLink> &types,
const utils::Vec<utils::Bool> &writable,
Expand Down Expand Up @@ -148,7 +148,7 @@ InstructionTypeLink find_instruction_type(
* from the old to new IR. See find_instruction_type().
*/
InstructionRef make_instruction(
const Ref &ir,
const PlatformRef &platform,
const utils::Str &name,
const utils::Any<Expression> &operands,
const ExpressionRef &condition = {},
Expand Down Expand Up @@ -245,7 +245,7 @@ utils::One<FunctionCall> make_function_call(
/**
* Returns the number of qubits in the main qubit register.
*/
utils::UInt get_num_qubits(const Ref &ir);
utils::UInt get_num_qubits(const PlatformRef &platform);

/**
* Makes an integer literal using the given or default integer type.
Expand All @@ -255,17 +255,17 @@ utils::One<IntLiteral> make_int_lit(const Ref &ir, utils::Int i, const DataTypeL
/**
* Makes an integer literal using the given or default integer type.
*/
utils::One<IntLiteral> make_uint_lit(const Ref &ir, utils::UInt i, const DataTypeLink &type = {});
utils::One<IntLiteral> make_uint_lit(const PlatformRef &platform, utils::UInt i, const DataTypeLink &type = {});

/**
* Makes an bit literal using the given or default bit type.
*/
utils::One<BitLiteral> make_bit_lit(const Ref &ir, utils::Bool b, const DataTypeLink &type = {});
utils::One<BitLiteral> make_bit_lit(const PlatformRef &platform, utils::Bool b, const DataTypeLink &type = {});

/**
* Makes a qubit reference to the main qubit register.
*/
utils::One<Reference> make_qubit_ref(const Ref &ir, utils::UInt idx);
utils::One<Reference> make_qubit_ref(const PlatformRef &platform, utils::UInt idx);

/**
* Makes a reference to the implicit measurement bit associated with a qubit in
Expand All @@ -277,7 +277,7 @@ utils::One<Reference> make_bit_ref(const Ref &ir, utils::UInt idx);
* Makes a reference to the specified object using literal indices.
*/
utils::One<Reference> make_reference(
const Ref &ir,
const PlatformRef &platform,
const ObjectLink &obj,
utils::Vec<utils::UInt> indices = {}
);
Expand Down Expand Up @@ -316,5 +316,134 @@ utils::UInt get_duration_of_block(const BlockBaseRef &block);
*/
utils::UInt get_number_of_qubits_involved(const InstructionRef &insn);

class OperandsHelper {
public:
OperandsHelper(const PlatformRef p, const CustomInstruction &instruction) : platform(p), instr(instruction) {};

utils::UInt getQubit(utils::UInt operandIndex) {
const auto& op = getOperand(operandIndex);

const auto& ref = op.as_reference();
if (!ref) {
QL_FATAL("Operand #" << operandIndex << " of instruction " << instr.instruction_type->name << " is not a reference.");
}

if (ref->target != platform->qubits) {
QL_FATAL("Operand #" << operandIndex << " of instruction " << instr.instruction_type->name << " is not a qubit.");
}

return ref->indices[0].as<IntLiteral>()->value;
}

utils::UInt getFloat(utils::UInt operandIndex) {
const auto& op = getOperand(operandIndex);

const auto real = op.as_real_literal();

if (!real) {
QL_FATAL("Operand #" << operandIndex << " of instruction " << instr.instruction_type->name << " is not a float.");
}

return real->value;
}

utils::UInt getInt(utils::UInt operandIndex) {
const auto& op = getOperand(operandIndex);

const auto integer = op.as_int_literal();

if (!integer) {
QL_FATAL("Operand #" << operandIndex << " of instruction " << instr.instruction_type->name << " is not an integer.");
}

return integer->value;
}

utils::UInt numberOfQubitOperands() {
auto& instr_type = *instr.instruction_type;
while (!instr_type.generalization.empty()) {
instr_type = *instr_type.generalization;
}

utils::UInt nQubitOperands = 0;
for (const auto& op: instr_type.operand_types) {
if (op->data_type->type() == NodeType::QubitType) {
++nQubitOperands;
}
}

return nQubitOperands;
}

utils::UInt get1QGateOperand() {
QL_ASSERT(numberOfQubitOperands() == 1);

for (utils::UInt i = 0; i < totalNumberOfOperands(); ++i) {
const auto& op = getOperand(i);

const auto ref = op.as_reference();
if (ref && ref->target == platform->qubits) {
return ref->indices[0].as<IntLiteral>()->value;
}
}

QL_FATAL("This is a bug");
}

std::pair<utils::UInt, utils::UInt> get2QGateOperands() {
QL_ASSERT(numberOfQubitOperands() == 2);

utils::UInt q1 = utils::MAX;
utils::UInt q2 = utils::MAX;

for (utils::UInt i = 0; i < totalNumberOfOperands(); ++i) {
const auto& op = getOperand(i);

const auto ref = op.as_reference();
if (ref && ref->target == platform->qubits) {
if (q1 == utils::MAX) {
q1 = ref->indices[0].as<IntLiteral>()->value;
} else if (q2 == utils::MAX) {
q2 = ref->indices[0].as<IntLiteral>()->value;
QL_ASSERT(q1 != q2);
} else {
QL_FATAL("Gate has more than 2 qubit operands!");
}
}
}
return std::make_pair(q1, q2);
}

bool isNN2QGate(std::function<utils::UInt(utils::UInt)> v2r) {
auto qubits = get2QGateOperands();

return platform->topology->get_min_hops(v2r(qubits.first), v2r(qubits.second)) == 1;
}

private:
const utils::UInt totalNumberOfOperands() {
return instr.instruction_type->template_operands.size() + instr.operands.size();
}

const Expression& getOperand(utils::UInt operandIndex) {
const auto& templateOperands = instr.instruction_type->template_operands;
const auto nTemplateOperands = templateOperands.size();

if (operandIndex < nTemplateOperands) {
return *templateOperands[operandIndex];
}

const auto nTotalOperands = nTemplateOperands + instr.operands.size();
if (operandIndex >= nTotalOperands) {
QL_FATAL("Tried to access operand #" << operandIndex << " of instruction " << instr.instruction_type->name << " which has only " << nTotalOperands << " operands.");
}

return *instr.operands[operandIndex - nTemplateOperands];
}

const PlatformRef platform;
const CustomInstruction &instr;
};

} // namespace ir
} // namespace ql
26 changes: 26 additions & 0 deletions include/ql/ir/swap_parameters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "ql/utils/num.h"

namespace ql {
namespace ir {

struct SwapParameters {
utils::Bool part_of_swap = false;
// at the end of the swap r0 stores v0 and r1 stores v1
utils::Int r0 = -1;
utils::Int r1 = -1;
utils::Int v0 = -1;
utils::Int v1 = -1;

// default constructor
SwapParameters() {}

// initializer list
SwapParameters(utils::Bool _part_of_swap, utils::Int _r0, utils::Int _r1, utils::Int _v0, utils::Int _v1)
: part_of_swap(_part_of_swap), r0(_r0), r1(_r1), v0(_v0), v1(_v1)
{}
};

}
}
4 changes: 2 additions & 2 deletions include/ql/pass/map/qubits/map/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct Options;
/**
* Qubit mapper pass.
*/
class MapQubitsPass : public pmgr::pass_types::ProgramTransformation {
class MapQubitsPass : public pmgr::pass_types::Transformation {
static bool is_pass_registered;

private:
Expand Down Expand Up @@ -70,7 +70,7 @@ class MapQubitsPass : public pmgr::pass_types::ProgramTransformation {
* Runs the qubit mapper.
*/
utils::Int run(
const ir::compat::ProgramRef &program,
const ir::Ref &ir,
const pmgr::pass_types::Context &context
) const override;

Expand Down
Loading

0 comments on commit 62efe42

Please sign in to comment.