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

Work on frontend support for NISQ-like conditional



Tracking Result* from mz and conditional/branching statements.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent a59b1eaf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -238,7 +238,7 @@ def ConditionalOp : QuantumOp<"ifElseOp", []> {
  let summary = "if-then-else operation conditioned on a quantum Measure";
  // Must be conditioned on a Result type
  let arguments = (ins ResultType:$result_bit);
  let results = (outs Variadic<AnyType>:$results);
  let results = (outs);
  let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion);
}

+10 −0
Original line number Diff line number Diff line
OPENQASM 3;
include "qelib1.inc";

qubit q;
bit c;
h q;
c = measure q;
if (c) {
    x q;
}
+24 −0
Original line number Diff line number Diff line
@@ -144,4 +144,28 @@ void ScopedSymbolTable::evaluate_const_global(const std::string variable_name,
  // add_symbol(variable_name, x, {"const"});
  return;
}

void ScopedSymbolTable::add_measure_bit_assignment(
    const mlir::Value &bit_var, const mlir::Value &result_var) {
  assert(result_var.getType().isa<mlir::OpaqueType>());
  bit_var_ptr_to_meas_result_var[bit_var.getAsOpaquePointer()] = result_var;
}

std::optional<mlir::Value>
ScopedSymbolTable::try_lookup_meas_result(const mlir::Value &bit_var) {
  const auto iter =
      bit_var_ptr_to_meas_result_var.find(bit_var.getAsOpaquePointer());
  if (iter != bit_var_ptr_to_meas_result_var.end()) {
    return iter->second;
  }
  return std::nullopt;
}

std::optional<mlir::Value>
ScopedSymbolTable::try_lookup_meas_result(const std::string &bit_var_name) {
  if (!has_symbol(bit_var_name)) {
    return std::nullopt;
  }
  return try_lookup_meas_result(get_symbol(bit_var_name));
}
}  // namespace qcor
 No newline at end of file
+11 −1
Original line number Diff line number Diff line
@@ -138,6 +138,12 @@ class ScopedSymbolTable {
  // Map Opaque Ptr of value to key in SymbolTable
  std::map<void*, std::string> replacement_helper;

  // Map Opaque Ptr of bit value to the originating Result* (from measure)
  // Note: after Measure, we perform a casting from Result* -> bool.
  // This map tracks the Result* returns by the measure op
  // so that we can trace the originating Result*.
  std::unordered_map<void *, mlir::Value> bit_var_ptr_to_meas_result_var;

public:
  template <typename T>
  T get_global_constant(const std::string variable_name) {
@@ -425,6 +431,10 @@ class ScopedSymbolTable {
    return array_qubit_symbol_name(qreg_name, std::to_string(index));
  }

  void add_measure_bit_assignment(const mlir::Value &bit_var,
                                  const mlir::Value &result_var);
  std::optional<mlir::Value> try_lookup_meas_result(const mlir::Value &bit_var);
  std::optional<mlir::Value> try_lookup_meas_result(const std::string &bit_var_name);
  ~ScopedSymbolTable() {}
};
}  // namespace qcor
 No newline at end of file
+67 −0
Original line number Diff line number Diff line
@@ -2,6 +2,61 @@
#include "expression_handler.hpp"
#include "qasm3_visitor.hpp"

namespace {
// ATM, we don't try to convert everything to the
// special Quantum If-Then-Else Op.
// Rather, we aim for very narrow use-case that we're sure
// that this can be done.
// i.e., this serve mainly as a stop-gap before fully-FTQC runtimes become
// available.

// Capture binary comparison conditional.
// Note: currently, only bit-level is modeled.
// (Some backends, e.g., Honeywell, support a richer set of comparison ops).
struct BitComparisonExpression {
  std::string var_name;
  bool comparison_value;
  BitComparisonExpression(const std::string &var, bool val)
      : var_name(var), comparison_value(val) {}
};

// Test if this is a simple bit check conditional:
// e.g.,
// if (b) or if (b==1), etc.
std::optional<BitComparisonExpression> tryParseSimpleBooleanExpression(
    qasm3Parser::BooleanExpressionContext &boolean_expr) {
  // std::cout << "conditional expr: " << boolean_expr.getText() << "\n";
  if (boolean_expr.comparsionExpression()) {
    auto &comp_expr = *(boolean_expr.comparsionExpression());
    if (comp_expr.expression().size() == 1) {
      return BitComparisonExpression(comp_expr.expression(0)->getText(), true);
    }
    if (comp_expr.expression().size() == 2 && comp_expr.relationalOperator()) {
      if (comp_expr.relationalOperator()->getText() == "==") {
        if (comp_expr.expression(1)->getText() == "1") {
          return BitComparisonExpression(comp_expr.expression(0)->getText(),
                                         true);
        } else {
          return BitComparisonExpression(comp_expr.expression(0)->getText(),
                                         false);
        }
      }
      if (comp_expr.relationalOperator()->getText() == "!=") {
        if (comp_expr.expression(1)->getText() == "1") {
          return BitComparisonExpression(comp_expr.expression(0)->getText(),
                                         false);
        } else {
          return BitComparisonExpression(comp_expr.expression(0)->getText(),
                                         true);
        }
      }
    }
  }

  return std::nullopt;
}
} // namespace

namespace qcor {
antlrcpp::Any qasm3_visitor::visitBranchingStatement(
    qasm3Parser::BranchingStatementContext* context) {
@@ -10,6 +65,18 @@ antlrcpp::Any qasm3_visitor::visitBranchingStatement(
  // Get the conditional expression
  auto conditional_expr = context->booleanExpression();

  auto bit_check_conditional =
      tryParseSimpleBooleanExpression(*conditional_expr);
  // Currently, we're only support If (not else yet)
  auto meas_var =
      symbol_table.try_lookup_meas_result(bit_check_conditional->var_name);
  if (bit_check_conditional.has_value() &&
      context->programBlock().size() == 1 && meas_var.has_value()) {
    std::cout << "This is a simple Measure check\n";
    auto nisqIfStmt = builder.create<mlir::quantum::ConditionalOp>(
        location, meas_var.value());
  }

  // Map it to a Value
  qasm3_expression_generator exp_generator(builder, symbol_table, file_name);
  exp_generator.visit(conditional_expr);
Loading