Skip to content
Open
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
4 changes: 4 additions & 0 deletions include/autoq/parsing/ExtendedDirac/EvaluationVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ struct EvaluationVisitor : public ExtendedDiracParserBaseVisitor {
std::set<char> usedVars; // record all variables currently used in {diracs : varcons} for preventing naming collision.
segment2split_t segment2split;
currentSplit_t currentSplit;
std::string currentSegmentFirstKet; // the first ket rewritten in the current tensor segment
int currentSegmentKetLength; // its number of qubits, or -1 before the first ket
segment2perm_t segment2perm;
perm_t currentPerm;
std::vector<size_t> remember_the_lengths_of_each_unit_position;
Expand All @@ -77,6 +79,8 @@ struct EvaluationVisitor : public ExtendedDiracParserBaseVisitor {
usedVars(),
segment2split(),
currentSplit(),
currentSegmentFirstKet(),
currentSegmentKetLength(-1),
segment2perm(),
currentPerm(),
remember_the_lengths_of_each_unit_position(),
Expand Down
68 changes: 46 additions & 22 deletions include/autoq/parsing/ExtendedDirac/EvaluationVisitorDirac.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,33 @@
}
}

// Splits a ket into its variable units (qubit intervals) and sets len to
// its total number of qubits.
strsplit_t ket_units(const std::string &vstr, const std::map<char, int> &localVar2len, int &len) {
strsplit_t intervals;
len = 0;
for (const auto &c : vstr) {
if ((c == '0') || (c == '1')) {
len++;
continue;
}
auto it = localVar2len.find(static_cast<char>(std::tolower(c)));
if (it != localVar2len.end()) {
intervals.push_back(unitsplit_t(len, len+it->second));
len += it->second;
} else {
it = globalVar2len.find(static_cast<char>(std::tolower(c)));
if (it != globalVar2len.end()) {
intervals.push_back(unitsplit_t(len, len+it->second));
len += it->second;
} else {
THROW_AUTOQ_ERROR("Undefined variable!");
}
}
}
return intervals;
}

std::any visitTerm(ExtendedDiracParser::TermContext *ctx) override {
if (mode == EXPAND_POWER_AND_DIRACS_AND_REWRITE_COMPLEMENT) {
auto vstr = ctx->VStr->getText();
Expand All @@ -161,32 +188,12 @@
return std::any_cast<std::string>((ctx->complex() == nullptr ? (ctx->SUB() != nullptr ? "-1" : "") : ctx->complex()->getText()) + "∑" + ctx->varcons()->getText() + "|" + vstr2 + "⟩");
}
} else if (mode == COLLECT_KETS_AND_COMPUTE_UNIT_DECOMPOSITION_INDICES) {
strsplit_t intervals;
std::map<char, int> localVar2len;
if (ctx->varcons() != nullptr) {
localVar2len = std::any_cast<std::map<char, int>>(visit(ctx->varcons()));
}
int len = 0;
for (const auto &c : ctx->VStr->getText()) {
if ((c == '0') || (c == '1')) {
len++;
continue;
}
auto it = localVar2len.find(static_cast<char>(std::tolower(c)));
if (it != localVar2len.end()) {
intervals.push_back(unitsplit_t(len, len+it->second));
len += it->second;
} else {
it = globalVar2len.find(static_cast<char>(std::tolower(c)));
if (it != globalVar2len.end()) {
intervals.push_back(unitsplit_t(len, len+it->second));
len += it->second;
} else {
THROW_AUTOQ_ERROR("Undefined variable!");
}
}
}
return intervals;
return ket_units(ctx->VStr->getText(), localVar2len, len);
} else if (mode == REWRITE_BY_UNIT_INDICES_AND_MAKE_ALL_VARS_DISTINCT) {
/***************************************************************/
// Check if there is some local variable using global characters.
Expand Down Expand Up @@ -214,6 +221,18 @@
}
/***************************************************************/
std::string vstr = ctx->VStr->getText();
/* All kets for the same qubits (in one set, across "∪", and across
the files of one verification task) must have the same length. */
int ketLength = 0;
ket_units(vstr, localVar2len, ketLength);
if (currentSegmentKetLength == -1) {
currentSegmentKetLength = ketLength;
currentSegmentFirstKet = vstr;
} else if (ketLength != currentSegmentKetLength) {
THROW_AUTOQ_ERROR("Not aligned: the ket |" + vstr + "⟩ has " + std::to_string(ketLength)
+ " qubit(s), but the ket |" + currentSegmentFirstKet + "⟩ for the same qubits has "
+ std::to_string(currentSegmentKetLength) + ".");
}
std::string vstr2; // the rewritten output
remember_the_lengths_of_each_unit_position.clear();
/*************************************************/
Expand All @@ -230,9 +249,14 @@
/***********************************************/
std::map<std::string, char> localVal2const;
for (const auto &[l, r] : completeCurrentSplit) {
if (vstr.empty()) {
if (r == -1) continue; // no remaining part
THROW_AUTOQ_ERROR("Not aligned!");
}
if (r == -1 || // the last remaining part not classified as a unit must be a constant
vstr.at(0)=='0' || vstr.at(0)=='1') {
if (vstr.empty()) continue; // reject if there is no remaining part
if (r != -1 && vstr.size() < static_cast<size_t>(r - l))
THROW_AUTOQ_ERROR("Not aligned!");
std::string this_constant_string = ((r == -1) ? vstr : vstr.substr(0, r-l));
if (!std::all_of(this_constant_string.begin(), this_constant_string.end(), [](char ch) { return ch == '0' || ch == '1'; })) {
THROW_AUTOQ_ERROR("Not aligned!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
if (ctx->scset() != nullptr) { // set
currentSplit = segment2split.front(); // access the first element
segment2split.erase(segment2split.begin()); // remove it (O(n) operation)
currentSegmentKetLength = -1;
return std::any_cast<std::string>(visit(ctx->scset()));
} else if (ctx->MUL() != nullptr || ctx->PROD() != nullptr) {
std::string str0 = std::any_cast<std::string>(visit(ctx->tset(0)));
Expand Down
14 changes: 14 additions & 0 deletions unit_tests/qasm_parsing_inclusion_cli_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ BOOST_AUTO_TEST_CASE(qasm_parsing_minimal_circuit)
+ AUTOQ::Serialization::TimbukSerializer::Serialize(spec));
}

// Kets for the same qubits must have the same length; otherwise parsing
// reports an AutoQError instead of aborting with std::out_of_range (#34).
BOOST_AUTO_TEST_CASE(misaligned_kets_are_rejected)
{
std::string folder = test_dir_from_file(__FILE__, "testcase/KetAlignment/");
using Parser = AUTOQ::Parsing::TimbukParser<Concrete>;
for (const std::string f : {"shorter_ket.hsl", "longer_ket.hsl", "ket_ends_inside_constant.hsl"})
BOOST_CHECK_THROW(Parser::ReadAutomaton(folder + f), AutoQError);
BOOST_CHECK_THROW(Parser::ReadTwoAutomata(folder + "pre.hsl", folder + "post_shorter.hsl", folder + "circuit.qasm"), AutoQError);

BOOST_CHECK_NO_THROW(Parser::ReadAutomaton(folder + "aligned.hsl"));
BOOST_CHECK_NO_THROW(Parser::ReadTwoAutomata(folder + "pre.hsl", folder + "post.hsl", folder + "circuit.qasm"));
}

BOOST_AUTO_TEST_CASE(inclusion_checker_equal_automata)
{
auto aut = AUTOQ::ConcreteAutomata::basis(3);
Expand Down
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/aligned.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|0x> : |x|=1} ∪ {|10>}
3 changes: 3 additions & 0 deletions unit_tests/testcase/KetAlignment/circuit.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OPENQASM 2.0;
include "qelib1.inc";
qreg qubits[2];
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/ket_ends_inside_constant.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|0x> : |x|=2} ∪ {|00>}
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/longer_ket.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|x> : |x|=1} ∪ {|00>}
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/post.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|00>}
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/post_shorter.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|0>}
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/pre.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|xy> : |x|=1, |y|=1}
2 changes: 2 additions & 0 deletions unit_tests/testcase/KetAlignment/shorter_ket.hsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extended Dirac
{|0x> : |x|=1} ∪ {|0>}
Loading