Commit b53781ca authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Update alias test to cover slice cases



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 3d323e71
Loading
Loading
Loading
Loading
+102 −24
Original line number Diff line number Diff line
@@ -2,17 +2,15 @@
#include "gtest/gtest.h"

TEST(qasm3VisitorTester, checkAlias) {
  {
    // Test 1: Alias by indices
  const std::string alias_by_indicies = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[6];
// Test 1: Alias by indices
// myreg[0,1,2] refers to the qubit q[1,3,5]
let myreg = q[1, 3, 5];
// Apply x on qubits in the alias list
for i in [0:3] {
  x myreg[i];
}
// Use broadcast to make sure it work
x myreg;
// Measure all qubits
bit m[6];
m = measure q;
@@ -26,39 +24,119 @@ QCOR_EXPECT_TRUE(m[2] == 0);
QCOR_EXPECT_TRUE(m[3] == 1);
QCOR_EXPECT_TRUE(m[4] == 0);
QCOR_EXPECT_TRUE(m[5] == 1);
)#";
    auto mlir = qcor::mlir_compile("qasm3", alias_by_indicies, "test",
                                   qcor::OutputType::MLIR, true);
    std::cout << "MLIR:\n" << mlir << "\n";
    EXPECT_FALSE(qcor::execute("qasm3", alias_by_indicies, "test"));
  }
// Reset q to start next test
reset q;
bit m1[6];
m1 = measure q;
QCOR_EXPECT_TRUE(m1[0] == 0);
QCOR_EXPECT_TRUE(m1[1] == 0);
QCOR_EXPECT_TRUE(m1[2] == 0);
QCOR_EXPECT_TRUE(m1[3] == 0);
QCOR_EXPECT_TRUE(m1[4] == 0);
QCOR_EXPECT_TRUE(m1[5] == 0);

// Test 2: Alias by slice:
  {
    const std::string alias_by_slice = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[6];
// Range without step size
// 0, 1, 2, 3 (inclusive)
let myreg1 = q[0:3];
x myreg1;
// Measure all qubits
bit m2[6];
m2 = measure q;

for j in [0:6] {
  print(m2[j]);
}
QCOR_EXPECT_TRUE(m2[0] == 1);
QCOR_EXPECT_TRUE(m2[1] == 1);
QCOR_EXPECT_TRUE(m2[2] == 1);
QCOR_EXPECT_TRUE(m2[3] == 1);
QCOR_EXPECT_TRUE(m2[4] == 0);
QCOR_EXPECT_TRUE(m2[5] == 0);

// Reset q to start next test
reset q;

// Range with step size (0, 2, 4)
let myreg2 = q[0:2:5];
x myreg2;
// Measure all qubits
bit m3[6];
m3 = measure q;

for k in [0:6] {
  print(m3[k]);
}
QCOR_EXPECT_TRUE(m3[0] == 1);
QCOR_EXPECT_TRUE(m3[1] == 0);
QCOR_EXPECT_TRUE(m3[2] == 1);
QCOR_EXPECT_TRUE(m3[3] == 0);
QCOR_EXPECT_TRUE(m3[4] == 1);
QCOR_EXPECT_TRUE(m3[5] == 0);

// Reset q to start next test
reset q;
// Range with negative step:
// 4, 3, 2
let myreg3 = q[4:-1:2];
x myreg3;
// Measure all qubits
bit m4[6];
m4 = measure q;

for i1 in [0:6] {
  print(m4[i1]);
}
QCOR_EXPECT_TRUE(m4[0] == 0);
QCOR_EXPECT_TRUE(m4[1] == 0);
QCOR_EXPECT_TRUE(m4[2] == 1);
QCOR_EXPECT_TRUE(m4[3] == 1);
QCOR_EXPECT_TRUE(m4[4] == 1);
QCOR_EXPECT_TRUE(m4[5] == 0);

// Reset q to start next test
reset q;
// Range with start = stop
// This is q[5]
let myreg4 = q[5:5];
x myreg4;
// Measure all qubits
bit m5[6];
m5 = measure q;

for i2 in [0:6] {
  print(m5[i2]);
}
QCOR_EXPECT_TRUE(m5[0] == 0);
QCOR_EXPECT_TRUE(m5[1] == 0);
QCOR_EXPECT_TRUE(m5[2] == 0);
QCOR_EXPECT_TRUE(m5[3] == 0);
QCOR_EXPECT_TRUE(m5[4] == 0);
QCOR_EXPECT_TRUE(m5[5] == 1);

// Reset q to start next test
reset q;
// Range using negative indexing:
// Last 3 qubits
let myreg5 = q[-4:-1];
let myreg5 = q[-3:-1];
x myreg5;
// Measure all qubits
bit m6[6];
m6 = measure q;

for i3 in [0:6] {
  print(m6[i3]);
}
QCOR_EXPECT_TRUE(m6[0] == 0);
QCOR_EXPECT_TRUE(m6[1] == 0);
QCOR_EXPECT_TRUE(m6[2] == 0);
QCOR_EXPECT_TRUE(m6[3] == 1);
QCOR_EXPECT_TRUE(m6[4] == 1);
QCOR_EXPECT_TRUE(m6[5] == 1);
)#";
    auto mlir = qcor::mlir_compile("qasm3", alias_by_slice, "test",
  auto mlir = qcor::mlir_compile("qasm3", alias_by_indicies, "test",
                                 qcor::OutputType::MLIR, true);
  std::cout << "MLIR:\n" << mlir << "\n";
    // EXPECT_FALSE(qcor::execute("qasm3", alias_by_slice, "test"));
  }
  EXPECT_FALSE(qcor::execute("qasm3", alias_by_indicies, "test"));
}

int main(int argc, char **argv) {
+56 −2
Original line number Diff line number Diff line
@@ -23,9 +23,35 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement(
  // register
  auto alias = context->Identifier()->getText();

  // Get the name and symbol Value of the original register
  // Get the name and symbol Value of the original register.
  // We need to determine the alias array size and cache it 
  // for broadcast to work on the result array.
  auto allocated_variable = context->indexIdentifier()->Identifier()->getText();
  auto allocated_symbol = symbol_table.get_symbol(allocated_variable);
  // Determine the first qreg size
  const auto get_qreg_size = [&](const std::string &qreg_name) {
    uint64_t nqubits;
    auto qreg_value = symbol_table.get_symbol(qreg_name);
    if (auto op = qreg_value.getDefiningOp<mlir::quantum::QallocOp>()) {
      nqubits = op.size().getLimitedValue();
    } else {
      auto attributes = symbol_table.get_variable_attributes(qreg_name);
      if (!attributes.empty()) {
        try {
          nqubits = std::stoi(attributes[0]);
        } catch (...) {
          printErrorMessage("Could not infer qubit[] size from block argument.",
                            context);
        }
      } else {
        printErrorMessage(
            "Could not infer qubit[] size from block argument. No size "
            "attribute for variable in symbol table.",
            context);
      }
    }
    return nqubits;
  };

  // handle q[1, 3, 5] comma syntax
  if (context->indexIdentifier()->LBRACKET()) {
@@ -42,7 +68,8 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement(
        builder.create<mlir::quantum::QaliasArrayAllocOp>(
            location, array_type, integer_attr, str_attr);
    // Add the alias register to the symbol table
    symbol_table.add_symbol(alias, alias_allocation);
    symbol_table.add_symbol(alias, alias_allocation,
                            {std::to_string(n_expressions)});

    auto counter = 0;
    for (auto expr : expressions) {
@@ -103,6 +130,33 @@ antlrcpp::Any qasm3_visitor::visitAliasStatement(
        location, array_type, allocated_symbol,
        llvm::makeArrayRef(std::vector<mlir::Value>{
            range_start_mlir_val, range_step_mlir_val, range_stop_mlir_val}));
    
    // Determine and cache the slice size for instruction broadcasting.
    const int64_t orig_size = get_qreg_size(allocated_variable);
    const auto slice_size_calc = [](int64_t orig_size, int64_t start,
                                    int64_t step, int64_t end) -> int64_t {
      // If step > 0 and lo > hi, or step < 0 and lo < hi, the range is empty.
      // Else for step > 0, if n values are in the range, the last one is
      // lo + (n-1)*step, which must be <= hi.  Rearranging,
      // n <= (hi - lo)/step + 1, so taking the floor of the RHS gives
      // the proper value.
      assert(step != 0);
      // Convert to positive indices (if given as negative)
      const int64_t lo = start >= 0 ? start : orig_size + start;
      const int64_t hi = end >= 0 ? end : orig_size + end;
      if (lo == hi) {
        return 1;
      }
      if (step > 0 && lo < hi) {
        return 1 + (hi - lo) / step;
      } else if (step < 0 && lo > hi) {
        return 1 + (lo - hi) / (-step);
      } else {
        return 0;
      }
    };
    const auto new_size = slice_size_calc(orig_size, range_start, range_step, range_stop);
    symbol_table.add_symbol(alias, array_slice, {std::to_string(new_size)});
  } else {
    // handle concatenation
  }
+1 −1
Original line number Diff line number Diff line
@@ -864,7 +864,7 @@ class QarraySliceOpLowering : public ConversionPattern {
    variables.insert({name.str(), slice_array_call.getResult(0)});

    // Remove the old QuantumDialect QarraySliceOp
    rewriter.eraseOp(op);
    rewriter.replaceOp(op, slice_array_call.getResult(0));

    return success();
  }