1 /* 2 * This file is part of qasmtools. 3 * 4 * Copyright (c) 2019 - 2021 softwareQ Inc. All rights reserved. 5 * 6 * MIT License 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 * SOFTWARE. 25 */ 26 27 /** 28 * \file qasmtools/ast/stmt.hpp 29 * \brief openQASM statements 30 */ 31 32 #pragma once 33 34 #include "base.hpp" 35 #include "expr.hpp" 36 #include "var.hpp" 37 38 #include <functional> 39 #include <vector> 40 41 namespace qasmtools { 42 namespace ast { 43 44 /** 45 * \class qasmtools::ast::Stmt 46 * \brief Base class for openQASM statements 47 */ 48 class Stmt : public ASTNode { 49 public: Stmt(parser::Position pos)50 Stmt(parser::Position pos) : ASTNode(pos) {} 51 virtual ~Stmt() = default; 52 virtual Stmt* clone() const override = 0; 53 54 /** 55 * \brief Internal pretty-printer which can suppress the output of the 56 * stdlib 57 * 58 * \param suppress_std Whether to suppress output of the standard library 59 */ 60 virtual std::ostream& pretty_print(std::ostream& os, 61 bool suppress_std) const = 0; 62 pretty_print(std::ostream & os) const63 std::ostream& pretty_print(std::ostream& os) const override { 64 return pretty_print(os, false); 65 } 66 }; 67 68 /** 69 * \class qasmtools::ast::MeasureStmt 70 * \brief Class for measurement statements 71 * \see qasmtools::ast::Stmt 72 */ 73 class MeasureStmt final : public Stmt { 74 VarAccess q_arg_; ///< the quantum bit|register 75 VarAccess c_arg_; ///< the classical bit|register 76 77 public: 78 /** 79 * \brief Constructs a measurement statement 80 * 81 * \param pos The source position 82 * \param q_arg Rvalue reference to the quantum argument 83 * \param c_arg Rvalue reference to the classical argument 84 */ MeasureStmt(parser::Position pos,VarAccess && q_arg,VarAccess && c_arg)85 MeasureStmt(parser::Position pos, VarAccess&& q_arg, VarAccess&& c_arg) 86 : Stmt(pos), q_arg_(std::move(q_arg)), c_arg_(std::move(c_arg)) {} 87 88 /** 89 * \brief Protected heap-allocated construction 90 */ create(parser::Position pos,VarAccess && q_arg,VarAccess && c_arg)91 static ptr<MeasureStmt> create(parser::Position pos, VarAccess&& q_arg, 92 VarAccess&& c_arg) { 93 return std::make_unique<MeasureStmt>(pos, std::move(q_arg), 94 std::move(c_arg)); 95 } 96 97 /** 98 * \brief Get the quantum argument 99 * 100 * \return Reference to the quantum argument 101 */ q_arg()102 VarAccess& q_arg() { return q_arg_; } 103 104 /** 105 * \brief Get the classical argument 106 * 107 * \return Reference to the classical argument 108 */ c_arg()109 VarAccess& c_arg() { return c_arg_; } 110 111 /** 112 * \brief Set the quantum argument 113 * 114 * \param arg Const reference to a new argument 115 */ set_qarg(const VarAccess & arg)116 void set_qarg(const VarAccess& arg) { q_arg_ = arg; } 117 118 /** 119 * \brief Set the classical argument 120 * 121 * \param arg Const reference to a new argument 122 */ set_carg(const VarAccess & arg)123 void set_carg(const VarAccess& arg) { c_arg_ = arg; } 124 accept(Visitor & visitor)125 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const126 std::ostream& pretty_print(std::ostream& os, bool) const override { 127 os << "measure " << q_arg_ << " -> " << c_arg_ << ";\n"; 128 return os; 129 } clone() const130 MeasureStmt* clone() const override { 131 return new MeasureStmt(pos_, VarAccess(q_arg_), VarAccess(c_arg_)); 132 } 133 }; 134 135 /** 136 * \class qasmtools::ast::ResetStmt 137 * \brief Class for reset statements 138 * \see qasmtools::ast::Stmt 139 */ 140 class ResetStmt final : public Stmt { 141 VarAccess arg_; ///< the qbit|qreg 142 143 public: 144 /** 145 * \brief Constructs a reset statement 146 * 147 * \param pos The source position 148 * \param arg Rvalue reference to the argument 149 */ ResetStmt(parser::Position pos,VarAccess && arg)150 ResetStmt(parser::Position pos, VarAccess&& arg) 151 : Stmt(pos), arg_(std::move(arg)) {} 152 153 /** 154 * \brief Protected heap-allocated construction 155 */ create(parser::Position pos,VarAccess && arg)156 static ptr<ResetStmt> create(parser::Position pos, VarAccess&& arg) { 157 return std::make_unique<ResetStmt>(pos, std::move(arg)); 158 } 159 160 /** 161 * \brief Get the argument 162 * 163 * \return Reference to the argument 164 */ arg()165 VarAccess& arg() { return arg_; } 166 167 /** 168 * \brief Set the argument 169 * 170 * \param arg Const reference to a new argument 171 */ set_arg(const VarAccess & arg)172 void set_arg(const VarAccess& arg) { arg_ = arg; } 173 accept(Visitor & visitor)174 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const175 std::ostream& pretty_print(std::ostream& os, bool) const override { 176 os << "reset " << arg_ << ";\n"; 177 return os; 178 } clone() const179 ResetStmt* clone() const override { 180 return new ResetStmt(pos_, VarAccess(arg_)); 181 } 182 }; 183 184 /** 185 * \class qasmtools::ast::IfStmt 186 * \brief Class for if statements 187 * \see qasmtools::ast::Stmt 188 */ 189 class IfStmt final : public Stmt { 190 symbol var_; ///< classical register name 191 int cond_; ///< value to check against 192 ptr<Stmt> then_; ///< statement to be executed if true 193 194 public: 195 /** 196 * \brief Constructs an if statement 197 * 198 * \param pos The source position 199 * \param var The variable (classical register) being tested 200 * \param cond The integer value to test against 201 * \param then The statement to execute in the then branch 202 */ IfStmt(parser::Position pos,symbol var,int cond,ptr<Stmt> then)203 IfStmt(parser::Position pos, symbol var, int cond, ptr<Stmt> then) 204 : Stmt(pos), var_(var), cond_(cond), then_(std::move(then)) {} 205 206 /** 207 * \brief Protected heap-allocated construction 208 */ create(parser::Position pos,symbol var,int cond,ptr<Stmt> then)209 static ptr<IfStmt> create(parser::Position pos, symbol var, int cond, 210 ptr<Stmt> then) { 211 return std::make_unique<IfStmt>(pos, var, cond, std::move(then)); 212 } 213 214 /** 215 * \brief Get the tested variable 216 * 217 * \return Const reference to the variable name 218 */ var() const219 const symbol& var() const { return var_; } 220 221 /** 222 * \brief Get the integer condition 223 * 224 * \return The integer tested against 225 */ cond() const226 int cond() const { return cond_; } 227 228 /** 229 * \brief Get the then branch 230 * 231 * \return Reference to the "then" statement 232 */ then()233 Stmt& then() { return *then_; } 234 235 /** 236 * \brief Set the then branch 237 * 238 * \param then The new statement 239 */ set_then(ptr<Stmt> then)240 void set_then(ptr<Stmt> then) { then_ = std::move(then); } 241 accept(Visitor & visitor)242 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const243 std::ostream& pretty_print(std::ostream& os, bool) const override { 244 os << "if (" << var_ << "==" << cond_ << ") " << *then_; 245 return os; 246 } clone() const247 IfStmt* clone() const override { 248 return new IfStmt(pos_, var_, cond_, ptr<Stmt>(then_->clone())); 249 } 250 }; 251 252 /** 253 * \class qasmtools::ast::Gate 254 * \brief Statement sub-class for gate 255 */ 256 class Gate : public Stmt { 257 public: Gate(parser::Position pos)258 Gate(parser::Position pos) : Stmt(pos) {} 259 virtual ~Gate() = default; 260 virtual Gate* clone() const = 0; 261 }; 262 263 /** 264 * \class qasmtools::ast::UGate 265 * \brief Class for U gates 266 * \see qasmtools::ast::Gate 267 */ 268 class UGate final : public Gate { 269 ptr<Expr> theta_; ///< theta angle 270 ptr<Expr> phi_; ///< phi angle 271 ptr<Expr> lambda_; ///< lambda angle 272 273 VarAccess arg_; ///< quantum bit|register 274 275 public: 276 /** 277 * \brief Constructs a U gate 278 * 279 * \param pos The source position 280 * \param theta The theta angle 281 * \param phi The phi angle 282 * \param lambda The lambda angle 283 * \param arg Rvalue reference to the quantum argument 284 */ UGate(parser::Position pos,ptr<Expr> theta,ptr<Expr> phi,ptr<Expr> lambda,VarAccess && arg)285 UGate(parser::Position pos, ptr<Expr> theta, ptr<Expr> phi, 286 ptr<Expr> lambda, VarAccess&& arg) 287 : Gate(pos), theta_(std::move(theta)), phi_(std::move(phi)), 288 lambda_(std::move(lambda)), arg_(std::move(arg)) {} 289 290 /** 291 * \brief Protected heap-allocated construction 292 */ create(parser::Position pos,ptr<Expr> theta,ptr<Expr> phi,ptr<Expr> lambda,VarAccess && arg)293 static ptr<UGate> create(parser::Position pos, ptr<Expr> theta, 294 ptr<Expr> phi, ptr<Expr> lambda, VarAccess&& arg) { 295 return std::make_unique<UGate>(pos, std::move(theta), std::move(phi), 296 std::move(lambda), std::move(arg)); 297 } 298 299 /** 300 * \brief Get the theta angle 301 * 302 * \return Reference to the angle expression 303 */ theta()304 Expr& theta() { return *theta_; } 305 306 /** 307 * \brief Get the phi angle 308 * 309 * \return Reference to the angle expression 310 */ phi()311 Expr& phi() { return *phi_; } 312 313 /** 314 * \brief Get the lambda angle 315 * 316 * \return Reference to the angle expression 317 */ lambda()318 Expr& lambda() { return *lambda_; } 319 320 /** 321 * \brief Get the argument 322 * 323 * \return Reference to the quantum argument 324 */ arg()325 VarAccess& arg() { return arg_; } 326 327 /** 328 * \brief Set the theta angle 329 * 330 * \param theta The new angle expression 331 */ set_theta(ptr<Expr> theta)332 void set_theta(ptr<Expr> theta) { theta_ = std::move(theta); } 333 334 /** 335 * \brief Set the phi angle 336 * 337 * \param theta The new angle expression 338 */ set_phi(ptr<Expr> phi)339 void set_phi(ptr<Expr> phi) { phi_ = std::move(phi); } 340 341 /** 342 * \brief Set the lambda angle 343 * 344 * \param theta The new angle expression 345 */ set_lambda(ptr<Expr> lambda)346 void set_lambda(ptr<Expr> lambda) { lambda_ = std::move(lambda); } 347 348 /** 349 * \brief Set the argument 350 * 351 * \param arg The new argument 352 */ set_arg(const VarAccess & arg)353 void set_arg(const VarAccess& arg) { arg_ = arg; } 354 accept(Visitor & visitor)355 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const356 std::ostream& pretty_print(std::ostream& os, bool) const override { 357 os << "U(" << *theta_ << "," << *phi_ << "," << *lambda_ << ") " << arg_ 358 << ";\n"; 359 return os; 360 } clone() const361 UGate* clone() const override { 362 return new UGate(pos_, ptr<Expr>(theta_->clone()), 363 ptr<Expr>(phi_->clone()), ptr<Expr>(lambda_->clone()), 364 VarAccess(arg_)); 365 } 366 }; 367 368 /** 369 * \class qasmtools::ast::CNOTGate 370 * \brief Class for CX gates 371 * \see qasmtools::ast::Gate 372 */ 373 class CNOTGate final : public Gate { 374 VarAccess ctrl_; ///< control qubit|qreg 375 VarAccess tgt_; ///< target qubit|qreg 376 377 public: 378 /** 379 * \brief Constructs a CNOT gate 380 * 381 * \param pos The source position 382 * \param ctrl Rvalue reference to the control argument 383 * \param tgt Rvalue reference to the target argument 384 */ CNOTGate(parser::Position pos,VarAccess && ctrl,VarAccess && tgt)385 CNOTGate(parser::Position pos, VarAccess&& ctrl, VarAccess&& tgt) 386 : Gate(pos), ctrl_(std::move(ctrl)), tgt_(std::move(tgt)) {} 387 388 /** 389 * \brief Protected heap-allocated construction 390 */ create(parser::Position pos,VarAccess && ctrl,VarAccess && tgt)391 static ptr<CNOTGate> create(parser::Position pos, VarAccess&& ctrl, 392 VarAccess&& tgt) { 393 return std::make_unique<CNOTGate>(pos, std::move(ctrl), std::move(tgt)); 394 } 395 396 /** 397 * \brief Get the control argument 398 * 399 * \return Reference to the quantum argument 400 */ ctrl()401 VarAccess& ctrl() { return ctrl_; } 402 403 /** 404 * \brief Get the target argument 405 * 406 * \return Reference to the quantum argument 407 */ tgt()408 VarAccess& tgt() { return tgt_; } 409 410 /** 411 * \brief Set the control argument 412 * 413 * \param ctrl The new argument 414 */ set_ctrl(const VarAccess & ctrl)415 void set_ctrl(const VarAccess& ctrl) { ctrl_ = ctrl; } 416 417 /** 418 * \brief Set the target argument 419 * 420 * \param tgt The new argument 421 */ set_tgt(const VarAccess & tgt)422 void set_tgt(const VarAccess& tgt) { tgt_ = tgt; } 423 accept(Visitor & visitor)424 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const425 std::ostream& pretty_print(std::ostream& os, bool) const override { 426 os << "CX " << ctrl_ << "," << tgt_ << ";\n"; 427 return os; 428 } clone() const429 CNOTGate* clone() const override { 430 return new CNOTGate(pos_, VarAccess(ctrl_), VarAccess(tgt_)); 431 } 432 }; 433 434 /** 435 * \class qasmtools::ast::BarrierGate 436 * \brief Class for barrier gates 437 * \see qasmtools::ast::Gate 438 */ 439 class BarrierGate final : public Gate { 440 std::vector<VarAccess> args_; ///< list of quantum bits|registers 441 442 public: 443 /** 444 * \brief Constructs a barrier gate 445 * 446 * \param pos The source position 447 * \param args Rvalue reference to a list of arguments 448 */ BarrierGate(parser::Position pos,std::vector<VarAccess> && args)449 BarrierGate(parser::Position pos, std::vector<VarAccess>&& args) 450 : Gate(pos), args_(std::move(args)) {} 451 452 /** 453 * \brief Protected heap-allocated construction 454 */ create(parser::Position pos,std::vector<VarAccess> && args)455 static ptr<BarrierGate> create(parser::Position pos, 456 std::vector<VarAccess>&& args) { 457 return std::make_unique<BarrierGate>(pos, std::move(args)); 458 } 459 460 /** 461 * \brief Get the number of arguments 462 * 463 * \return The number of arguments 464 */ num_args() const465 int num_args() const { return static_cast<int>(args_.size()); } 466 467 /** 468 * \brief Get the list of arguments 469 * 470 * \return Reference to the list of arguments 471 */ args()472 std::vector<VarAccess>& args() { return args_; } 473 474 /** 475 * \brief Get the ith argument 476 * 477 * \param i The number of the argument (0 indexed) 478 * \return Reference to the ith argument 479 */ arg(int i)480 VarAccess& arg(int i) { return args_[i]; } 481 482 /** 483 * \brief Apply a function to each argument 484 * 485 * \param f Void function accepting a reference to the argument 486 */ foreach_arg(std::function<void (VarAccess &)> f)487 void foreach_arg(std::function<void(VarAccess&)> f) { 488 for (auto it = args_.begin(); it != args_.end(); it++) 489 f(*it); 490 } 491 492 /** 493 * \brief Set the ith argument 494 * 495 * \param i The number of the argument (0 indexed) 496 * \param arg The new argument 497 */ set_arg(int i,const VarAccess & arg)498 void set_arg(int i, const VarAccess& arg) { args_[i] = arg; } 499 accept(Visitor & visitor)500 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const501 std::ostream& pretty_print(std::ostream& os, bool) const override { 502 os << "barrier "; 503 for (auto it = args_.begin(); it != args_.end(); it++) { 504 os << (it == args_.begin() ? "" : ",") << *it; 505 } 506 os << ";\n"; 507 return os; 508 } clone() const509 BarrierGate* clone() const override { 510 return new BarrierGate(pos_, std::vector<VarAccess>(args_)); 511 } 512 }; 513 514 /** 515 * \class qasmtools::ast::DeclaredGate 516 * \brief Class for declared gate applications 517 * \see qasmtools::ast::Gate 518 */ 519 class DeclaredGate final : public Gate { 520 symbol name_; ///< gate identifier 521 std::vector<ptr<Expr>> c_args_; ///< list of classical arguments 522 std::vector<VarAccess> q_args_; ///< list of quantum arguments 523 524 public: 525 /** 526 * \brief Constructs an application of a declared gate 527 * 528 * \param pos The source position 529 * \param name The gate name 530 * \param c_args Rvalue reference to a list of classical arguments 531 * \param q_args Rvalue reference to a list of quantum arguments 532 */ DeclaredGate(parser::Position pos,symbol name,std::vector<ptr<Expr>> && c_args,std::vector<VarAccess> && q_args)533 DeclaredGate(parser::Position pos, symbol name, 534 std::vector<ptr<Expr>>&& c_args, 535 std::vector<VarAccess>&& q_args) 536 : Gate(pos), name_(name), c_args_(std::move(c_args)), 537 q_args_(std::move(q_args)) {} 538 539 /** 540 * \brief Protected heap-allocated construction 541 */ create(parser::Position pos,symbol name,std::vector<ptr<Expr>> && c_args,std::vector<VarAccess> && q_args)542 static ptr<DeclaredGate> create(parser::Position pos, symbol name, 543 std::vector<ptr<Expr>>&& c_args, 544 std::vector<VarAccess>&& q_args) { 545 return std::make_unique<DeclaredGate>(pos, name, std::move(c_args), 546 std::move(q_args)); 547 } 548 549 /** 550 * \brief Get the gate name 551 * 552 * \return Const reference to the gate name 553 */ name() const554 const symbol& name() const { return name_; } 555 556 /** 557 * \brief Get the number of classical arguments 558 * 559 * \return The number of arguments 560 */ num_cargs() const561 int num_cargs() const { return static_cast<int>(c_args_.size()); } 562 563 /** 564 * \brief Get the number of quantum arguments 565 * 566 * \return The number of arguments 567 */ num_qargs() const568 int num_qargs() const { return static_cast<int>(q_args_.size()); } 569 570 /** 571 * \brief Get the ith classical argument 572 * 573 * \param i The number of the argument, 0-indexed 574 * \return Reference to an expression 575 */ carg(int i)576 Expr& carg(int i) { return *(c_args_[i]); } 577 578 /** 579 * \brief Get the ith quantum argument 580 * 581 * \param i The number of the argument, 0-indexed 582 * \return Reference to the argument 583 */ qarg(int i)584 VarAccess& qarg(int i) { return q_args_[i]; } 585 586 /** 587 * \brief Get the list of quantum arguments 588 * 589 * \return Reference to the list of arguments 590 */ qargs()591 std::vector<VarAccess>& qargs() { return q_args_; } 592 593 /** 594 * \brief Apply a function to each classical argument 595 * 596 * \param f Void function accepting an expression reference 597 */ foreach_carg(std::function<void (Expr &)> f)598 void foreach_carg(std::function<void(Expr&)> f) { 599 for (auto it = c_args_.begin(); it != c_args_.end(); it++) 600 f(**it); 601 } 602 603 /** 604 * \brief Apply a function to each quantum argument 605 * 606 * \param f Void function accepting a reference to an argument 607 */ foreach_qarg(std::function<void (VarAccess &)> f)608 void foreach_qarg(std::function<void(VarAccess&)> f) { 609 for (auto it = q_args_.begin(); it != q_args_.end(); it++) 610 f(*it); 611 } 612 613 /** 614 * \brief Set the ith classical argument 615 * 616 * \param i The number of the argument, 0-indexed 617 * \param expr An expression giving the new argument 618 */ set_carg(int i,ptr<Expr> expr)619 void set_carg(int i, ptr<Expr> expr) { c_args_[i] = std::move(expr); } 620 621 /** 622 * \brief Set the ith quantum argument 623 * 624 * \param i The number of the argument, 0-indexed 625 * \param arg The new argument 626 */ set_qarg(int i,const VarAccess & arg)627 void set_qarg(int i, const VarAccess& arg) { q_args_[i] = arg; } 628 accept(Visitor & visitor)629 void accept(Visitor& visitor) override { visitor.visit(*this); } pretty_print(std::ostream & os,bool) const630 std::ostream& pretty_print(std::ostream& os, bool) const override { 631 os << name_; 632 if (c_args_.size() > 0) { 633 os << "("; 634 for (auto it = c_args_.begin(); it != c_args_.end(); it++) { 635 os << (it == c_args_.begin() ? "" : ",") << **it; 636 } 637 os << ")"; 638 } 639 os << " "; 640 for (auto it = q_args_.begin(); it != q_args_.end(); it++) { 641 os << (it == q_args_.begin() ? "" : ",") << *it; 642 } 643 os << ";\n"; 644 return os; 645 } clone() const646 DeclaredGate* clone() const override { 647 std::vector<ptr<Expr>> c_tmp; 648 for (auto it = c_args_.begin(); it != c_args_.end(); it++) { 649 c_tmp.emplace_back(ptr<Expr>((*it)->clone())); 650 } 651 652 return new DeclaredGate(pos_, name_, std::move(c_tmp), 653 std::vector<VarAccess>(q_args_)); 654 } 655 }; 656 657 } // namespace ast 658 } // namespace qasmtools 659