38 using ident = std::string;
43 enum class BinaryOp { Plus, Minus, Times, Divide, Pow };
48 enum class UnaryOp { Neg, Sin, Cos, Tan, Ln, Sqrt, Exp };
50 static const Gates& gt = Gates::get_instance();
51 static std::unordered_map<ident,
52 std::function<cmat(const std::vector<double>&)>>
55 {
"cx", [](
const std::vector<double>&) {
return gt.CNOT; }},
56 {
"id", [](
const std::vector<double>&) {
return gt.Id2; }},
57 {
"x", [](
const std::vector<double>&) {
return gt.X; }},
58 {
"y", [](
const std::vector<double>&) {
return gt.Y; }},
59 {
"z", [](
const std::vector<double>&) {
return gt.Z; }},
60 {
"h", [](
const std::vector<double>&) {
return gt.H; }},
61 {
"s", [](
const std::vector<double>&) {
return gt.S; }},
62 {
"sdg", [](
const std::vector<double>&) {
return gt.S.adjoint(); }},
63 {
"t", [](
const std::vector<double>&) {
return gt.T; }},
64 {
"tdg", [](
const std::vector<double>&) {
return gt.T.adjoint(); }},
66 [](
const std::vector<double>& args) {
67 assert(args.size() > 0);
68 return gt.RX(args[0]);
71 [](
const std::vector<double>& args) {
72 assert(args.size() > 0);
73 return gt.RZ(args[0]);
76 [](
const std::vector<double>& args) {
77 assert(args.size() > 0);
78 return gt.RY(args[0]);
80 {
"cz", [](
const std::vector<double>&) {
return gt.CZ; }},
82 [](
const std::vector<double>&) {
83 cmat mat{cmat::Identity(4, 4)};
84 mat.block(2, 2, 2, 2) = gt.Y;
87 {
"swap", [](
const std::vector<double>&) {
return gt.SWAP; }},
89 [](
const std::vector<double>&) {
90 cmat mat{cmat::Identity(4, 4)};
91 mat.block(2, 2, 2, 2) = gt.H;
94 {
"ccx", [](
const std::vector<double>&) {
return gt.TOF; }},
95 {
"crz", [](
const std::vector<double>& args) {
96 assert(args.size() > 0);
97 cmat mat{cmat::Identity(4, 4)};
98 mat.block(2, 2, 2, 2) = gt.RZ(args[0]);
111 virtual ~Value() =
default;
127 using hash_ident_uptr = std::unordered_map<ident, std::unique_ptr<Value>>;
129 Environment() noexcept : val_(){};
130 Environment(Environment&& rhs) noexcept : val_(std::move(rhs.val_)) {}
131 hash_ident_uptr val_;
134 std::vector<Environment> env_{};
135 std::list<idx> qubit_pool_{};
140 std::vector<idx> cctrls_{};
141 std::vector<idx> cctrl_shift_{};
149 Context(QCircuit* qc) : circuit_(qc) {}
154 Context(
const Context&) =
delete;
159 Context& operator=(
const Context&) =
delete;
166 QCircuit* get_circuit() {
return circuit_; }
176 idx ret = ++max_bit_;
179 if (max_bit_ >= circuit_->get_nc()) {
180 circuit_->add_dit(1, ret);
192 idx ret = ++max_qubit_;
195 if (max_qubit_ >= circuit_->get_nq()) {
196 circuit_->add_qudit(1, ret);
206 void enter_scope() { env_.push_back({}); }
211 void exit_scope() { env_.pop_back(); }
223 Value* lookup(
const ident&
id,
const Location& loc) {
224 for (
auto table = env_.rbegin(); table != env_.rend(); table++) {
225 auto it = table->val_.find(
id);
226 if (it != table->val_.end())
227 return it->second.get();
230 std::cerr << loc <<
": Undeclared identifier " <<
id <<
"\n";
231 throw exception::Undeclared(
"qpp::qasm::Context::lookup()");
241 void set(
const ident& id, std::unique_ptr<Value> val) {
244 env_.back().val_[id] = std::move(val);
255 void set_ccontrols(
const std::vector<idx>& cctrls,
256 const std::vector<idx>& shift) {
258 cctrl_shift_ = shift;
264 void clear_ccontrols() {
266 cctrl_shift_.clear();
274 bool ccontrolled() {
return !cctrls_.empty(); }
281 const std::vector<idx>& get_cctrls() {
return cctrls_; }
288 const std::vector<idx>& get_shift() {
return cctrl_shift_; }
297 class Statement :
public IDisplay {
307 Statement(Location loc) : loc_(loc) {}
312 Statement(
const Statement&) =
delete;
317 virtual ~Statement() =
default;
327 virtual void evaluate(Context& ctx)
const = 0;
335 void pretty_print(std::ostream& os,
const std::string& prefix)
const {
336 os <<
"(" << loc_ <<
"):" << prefix << *
this;
339 using StatementPtr = std::unique_ptr<Statement>;
345 class Gate :
public Statement {
352 Gate(Location loc) : Statement(loc) {}
357 Gate(
const Gate&) =
delete;
362 virtual ~Gate() =
default;
364 using GatePtr = std::unique_ptr<Gate>;
371 class Decl :
public Statement {
382 Decl(Location loc, ident
id) : Statement(loc), id_(id) {}
387 Decl(
const Decl&) =
delete;
392 virtual ~Decl() =
default;
399 class Expr :
public IDisplay {
409 Expr(Location loc) : loc_(loc) {}
414 Expr(
const Expr&) =
delete;
419 virtual ~Expr() =
default;
429 virtual double evaluate(Context& ctx)
const = 0;
431 using ExprPtr = std::unique_ptr<Expr>;
438 class QASM :
public IDisplay {
441 std::vector<StatementPtr> body_;
452 QASM(
int bits,
int qubits, std::vector<StatementPtr>&& body)
453 : bits_(bits), qubits_(qubits), body_(std::move(body)) {}
460 std::unique_ptr<QCircuit> to_QCircuit() {
461 auto ret = std::unique_ptr<QCircuit>(
new QCircuit(qubits_, bits_));
462 Context ctx(ret.get());
463 for (
auto it = body_.begin(); it != body_.end(); it++) {
464 (*it)->evaluate(ctx);
473 std::ostream& display(std::ostream& os)
const {
474 os <<
"OPENQASM 2.0;\ninclude \"qelib1.inc\";\n";
475 for (
auto it = body_.begin(); it != body_.end(); it++) {
488 void pretty_print(std::ostream& os)
const {
489 os <<
"(Included header): OPENQASM 2.0;\n(Included header): include " 491 for (
auto it = body_.begin(); it != body_.end(); it++) {
492 (*it)->pretty_print(os,
"\t");
502 class Circuit :
public Value {
504 const std::vector<ident>& c_params_;
505 const std::vector<ident>& q_params_;
506 const std::vector<GatePtr>& body_;
508 Circuit(
const std::vector<ident>& c_params,
509 const std::vector<ident>& q_params,
510 const std::vector<GatePtr>& body)
511 : c_params_(c_params), q_params_(q_params), body_(body) {}
512 ~Circuit() =
default;
520 class Register :
public Value {
523 std::vector<idx> indices_;
525 Register(
bool quantum, std::vector<idx> indices)
526 : quantum_(quantum), indices_(indices) {}
527 ~Register() =
default;
535 class Qubit :
public Value {
539 Qubit(idx index) : index_(index) {}
548 class Number :
public Value {
552 Number(
double value) : value_(value) {}
560 class Varinfo :
public IDisplay {
573 Varinfo(Location loc, ident
id,
int offset = -1)
574 : loc_(loc), id_(id), offset_(offset) {}
583 std::vector<idx> as_creg(Context& ctx)
const {
584 auto reg =
dynamic_cast<const Register*
>(ctx.lookup(id_, loc_));
586 if (reg ==
nullptr || reg->quantum_) {
587 std::cerr << loc_ <<
": Identifier " << id_
588 <<
" does not refer to a bit register\n";
589 throw exception::SemanticError(
"qpp::qasm::Varinfo::as_creg()");
594 return std::vector<idx>{reg->indices_};
599 if ((idx) offset_ >= reg->indices_.size()) {
600 std::cerr << loc_ <<
": Index out of bounds\n";
601 throw exception::SemanticError(
"qpp::qasm::Varinfo::as_qreg()");
604 return std::vector<idx>{reg->indices_[offset_]};
616 std::vector<idx> as_qreg(Context& ctx)
const {
619 auto tmp = ctx.lookup(id_, loc_);
621 if (
auto qubit = dynamic_cast<const Qubit*>(tmp)) {
622 return std::vector<idx>{qubit->index_};
624 auto reg =
dynamic_cast<const Register*
>(tmp);
626 if (reg ==
nullptr || !reg->quantum_) {
627 std::cerr << loc_ <<
": Identifier " << id_
628 <<
" does not refer to a qubit register\n";
629 throw exception::SemanticError(
630 "qpp::qasm::Varinfo::as_qreg()");
633 return std::vector<idx>{reg->indices_};
637 auto reg =
dynamic_cast<const Register*
>(ctx.lookup(id_, loc_));
640 if (reg ==
nullptr || !reg->quantum_) {
641 std::cerr << loc_ <<
": Identifier " << id_
642 <<
" does not refer to a qubit register\n";
643 throw exception::SemanticError(
"qpp::qasm::Varinfo::as_qreg()");
647 if ((idx) offset_ >= reg->indices_.size()) {
648 std::cerr << loc_ <<
": Index out of bounds\n";
649 throw exception::SemanticError(
"qpp::qasm::Varinfo::as_qreg()");
652 return std::vector<idx>{reg->indices_[offset_]};
659 std::ostream& display(std::ostream& os)
const {
662 os <<
"[" << offset_ <<
"]";
673 class GateDecl final :
public Decl {
675 std::vector<ident> c_params_;
676 std::vector<ident> q_params_;
677 std::vector<GatePtr> body_;
689 GateDecl(Location loc, ident
id,
bool opaque, std::vector<ident> c_params,
690 std::vector<ident> q_params, std::vector<GatePtr> body)
691 : Decl(loc, id), opaque_(opaque), c_params_(c_params),
692 q_params_(q_params), body_(std::move(body)) {}
697 void evaluate(Context& ctx)
const {
698 ctx.set(id_, std::unique_ptr<Value>(
699 new Circuit(c_params_, q_params_, body_)));
705 std::ostream& display(std::ostream& os)
const {
706 os << (opaque_ ?
"opaque " :
"gate ") << id_;
707 if (c_params_.size() > 0) {
709 for (
auto it = c_params_.begin(); it != c_params_.end(); it++) {
710 os << (it == c_params_.begin() ?
"" :
",") << *it;
715 for (
auto it = q_params_.begin(); it != q_params_.end(); it++) {
716 os << (it == q_params_.begin() ?
"" :
",") << *it;
722 for (
auto it = body_.begin(); it != body_.end(); it++) {
734 void pretty_print(std::ostream& os,
const std::string& prefix)
const {
735 os <<
"(" << loc_ <<
"):" << prefix;
736 os << (opaque_ ?
"opaque " :
"gate ") << id_;
737 if (c_params_.size() > 0) {
739 for (
auto it = c_params_.begin(); it != c_params_.end(); it++) {
740 os << (it == c_params_.begin() ?
"" :
",") << *it;
745 for (
auto it = q_params_.begin(); it != q_params_.end(); it++) {
746 os << (it == q_params_.begin() ?
"" :
",") << *it;
751 auto nprefix = prefix +
"\t";
753 for (
auto it = body_.begin(); it != body_.end(); it++) {
754 (*it)->pretty_print(os, nprefix);
756 os <<
"(" << loc_ <<
"):" << prefix <<
"}\n";
766 class RegisterDecl final :
public Decl {
779 RegisterDecl(Location loc, ident
id,
bool quantum, idx length)
780 : Decl(loc, id), quantum_(quantum), length_(length) {}
785 void evaluate(Context& ctx)
const {
786 std::vector<idx> indices(length_);
787 for (idx i = 0; i < length_; i++) {
788 indices[i] = quantum_ ? ctx.alloc_qubit() : ctx.alloc_bit();
791 ctx.set(id_, std::unique_ptr<Value>(
new Register(quantum_, indices)));
797 std::ostream& display(std::ostream& os)
const {
798 os << (quantum_ ?
"qreg " :
"creg ") << id_ <<
"[" << length_ <<
"];\n";
808 class MeasureStatement final :
public Statement {
820 MeasureStatement(Location loc, Varinfo q_arg, Varinfo c_arg)
821 : Statement(loc), q_arg_(q_arg), c_arg_(c_arg) {}
826 void evaluate(Context& ctx)
const {
827 auto q_args = q_arg_.as_qreg(ctx);
828 auto c_args = c_arg_.as_creg(ctx);
829 auto circuit = ctx.get_circuit();
832 if (q_args.size() != c_args.size()) {
833 std::cerr <<
"(" << loc_ <<
"): Registers have different lengths\n";
834 throw exception::ParseError(
835 "qpp::qasm::MeasureStatement::evaluate()");
839 for (idx i = 0; i < q_args.size(); i++) {
840 circuit->measureZ(q_args[i], c_args[i],
false);
847 std::ostream& display(std::ostream& os)
const {
848 os <<
"measure " << q_arg_ <<
" -> " << c_arg_ <<
";\n";
858 class ResetStatement final :
public Statement {
868 ResetStatement(Location loc, Varinfo arg) : Statement(loc), arg_(arg) {}
873 void evaluate(Context& ctx)
const {
874 auto q_args = arg_.as_qreg(ctx);
875 auto circuit = ctx.get_circuit();
877 circuit->reset(q_args);
883 std::ostream& display(std::ostream& os)
const {
884 os <<
"reset " << arg_ <<
";\n";
894 class IfStatement final :
public Statement {
908 IfStatement(Location loc, ident
id,
int value, StatementPtr then)
909 : Statement(loc), id_(id), value_(value), then_(std::move(then)) {}
914 void evaluate(Context& ctx)
const {
915 auto creg =
dynamic_cast<const Register*
>(ctx.lookup(id_, loc_));
918 if (creg ==
nullptr || creg->quantum_) {
919 std::cerr << loc_ <<
": Identifier " << id_
920 <<
" does not refer to a classic register\n";
921 throw exception::SemanticError(
922 "qpp::qasm::IfStatement::evaluate()");
927 std::vector<idx> shift(creg->indices_.size(), 0);
928 for (idx i = 0; i < creg->indices_.size(); i++) {
935 ctx.set_ccontrols(creg->indices_, shift);
936 then_->evaluate(ctx);
937 ctx.clear_ccontrols();
943 std::ostream& display(std::ostream& os)
const {
944 os <<
"if (" << id_ <<
"==" << value_ <<
") " << *then_;
954 class UGate final :
public Gate {
970 UGate(Location loc, ExprPtr theta, ExprPtr phi, ExprPtr lambda, Varinfo arg)
971 : Gate(loc), theta_(std::move(theta)), phi_(std::move(phi)),
972 lambda_(std::move(lambda)), arg_(arg) {}
977 void evaluate(Context& ctx)
const {
978 auto theta = theta_->evaluate(ctx);
979 auto phi = phi_->evaluate(ctx);
980 auto lambda = lambda_->evaluate(ctx);
981 auto args = arg_.as_qreg(ctx);
982 auto circuit = ctx.get_circuit();
985 cmat u{cmat::Zero(2, 2)};
998 u << cos(theta / 2), -(sin(theta / 2)) * std::exp(1_i * lambda),
999 sin(theta / 2) * std::exp(1_i * phi),
1000 cos(theta / 2) * std::exp(1_i * (phi + lambda));
1003 for (
auto i : args) {
1004 if (ctx.ccontrolled()) {
1005 circuit->cCTRL(u, ctx.get_cctrls(), i, ctx.get_shift(),
1008 circuit->gate(u, i,
"U");
1016 std::ostream& display(std::ostream& os)
const {
1017 os <<
"U(" << *theta_ <<
"," << *phi_ <<
"," << *lambda_ <<
") " << arg_
1028 class CNOTGate final :
public Gate {
1040 CNOTGate(Location loc, Varinfo ctrl, Varinfo tgt)
1041 : Gate(loc), ctrl_(ctrl), tgt_(tgt) {}
1046 void evaluate(Context& ctx)
const {
1047 auto ctrls = ctrl_.as_qreg(ctx);
1048 auto tgts = tgt_.as_qreg(ctx);
1049 auto circuit = ctx.get_circuit();
1052 if (ctrls.size() == 1 && tgts.size() == 1) {
1053 if (ctx.ccontrolled()) {
1054 std::vector<idx> tmp{ctrls[0], tgts[0]};
1055 circuit->cCTRL_custom(gt.CNOT, ctx.get_cctrls(), tmp,
1056 ctx.get_shift(),
"CX");
1058 circuit->gate(gt.CNOT, ctrls[0], tgts[0],
"CX");
1060 }
else if (ctrls.size() > 1 && tgts.size() == 1) {
1061 for (idx i = 0; i < ctrls.size(); i++) {
1062 if (ctx.ccontrolled()) {
1063 std::vector<idx> tmp{ctrls[i], tgts[0]};
1064 circuit->cCTRL_custom(gt.CNOT, ctx.get_cctrls(), tmp,
1065 ctx.get_shift(),
"CX");
1067 circuit->gate(gt.CNOT, ctrls[i], tgts[0],
"CX");
1070 }
else if (ctrls.size() == 1 && tgts.size() > 1) {
1071 for (idx i = 0; i < tgts.size(); i++) {
1072 if (ctx.ccontrolled()) {
1073 std::vector<idx> tmp{ctrls[0], tgts[i]};
1074 circuit->cCTRL_custom(gt.CNOT, ctx.get_cctrls(), tmp,
1075 ctx.get_shift(),
"CX");
1077 circuit->gate(gt.CNOT, ctrls[0], tgts[i],
"CX");
1080 }
else if (ctrls.size() == tgts.size()) {
1081 for (idx i = 0; i < ctrls.size(); i++) {
1082 if (ctx.ccontrolled()) {
1083 std::vector<idx> tmp{ctrls[i], tgts[i]};
1084 circuit->cCTRL_custom(gt.CNOT, ctx.get_cctrls(), tmp,
1085 ctx.get_shift(),
"CX");
1087 circuit->gate(gt.CNOT, ctrls[i], tgts[i],
"CX");
1091 std::cerr << loc_ <<
": Registers have different lengths\n";
1092 throw exception::SemanticError(
"qpp::qasm::CNOTGate::evaluate()");
1099 std::ostream& display(std::ostream& os)
const {
1100 os <<
"CX " << ctrl_ << tgt_ <<
";\n";
1110 class BarrierGate final :
public Gate {
1111 std::vector<Varinfo> args_;
1120 BarrierGate(Location loc, std::vector<Varinfo> args)
1121 : Gate(loc), args_(args) {}
1126 void evaluate(Context& ctx)
const {
1128 idx mapping_size = 1;
1130 for (
auto& arg : args_) {
1131 auto tmp = arg.as_qreg(ctx);
1132 if (tmp.size() > 1) {
1133 if (mapping_size == 1) {
1134 mapping_size = tmp.size();
1135 }
else if (mapping_size != tmp.size()) {
1136 std::cerr << loc_ <<
": Registers have different lengths\n";
1137 throw exception::SemanticError(
1138 "qpp::qasm::BarrierGate::evaluate()");
1147 std::ostream& display(std::ostream& os)
const {
1149 for (
auto it = args_.begin(); it != args_.end(); it++) {
1150 os << (it == args_.begin() ?
"" :
",") << *it;
1162 class DeclaredGate final :
public Gate {
1164 std::vector<ExprPtr> c_args_;
1165 std::vector<Varinfo> q_args_;
1176 DeclaredGate(Location loc, ident
id, std::vector<ExprPtr>&& c_args,
1177 std::vector<Varinfo> q_args)
1178 : Gate(loc), id_(id), c_args_(std::move(c_args)),
1179 q_args_(std::move(q_args)) {}
1184 void evaluate(Context& ctx)
const {
1185 auto gate =
dynamic_cast<const Circuit*
>(ctx.lookup(id_, loc_));
1188 if (gate ==
nullptr) {
1189 std::cerr << loc_ <<
": Identifier " << id_
1190 <<
" does not refer to a gate declaration\n";
1191 throw exception::SemanticError(
1192 "qpp::qasm::DeclaredGate::evaluate()");
1196 if (c_args_.size() != gate->c_params_.size()) {
1197 std::cerr << loc_ <<
": " << id_ <<
" expects " 1198 << gate->c_params_.size();
1199 std::cerr <<
" classic arguments, got " << c_args_.size() <<
"\n";
1200 throw exception::SemanticError(
1201 "qpp::qasm::DeclaredGate::evaluate()");
1202 }
else if (q_args_.size() != gate->q_params_.size()) {
1203 std::cerr << loc_ <<
": " << id_ <<
" expects " 1204 << gate->q_params_.size();
1205 std::cerr <<
" quantum arguments, got " << q_args_.size() <<
"\n";
1206 throw exception::SemanticError(
1207 "qpp::qasm::DeclaredGate::evaluate()");
1211 std::vector<double> c_args(c_args_.size());
1212 std::vector<std::vector<idx>> q_args(q_args_.size());
1213 for (idx i = 0; i < c_args_.size(); i++)
1214 c_args[i] = c_args_[i]->evaluate(ctx);
1215 for (idx i = 0; i < q_args_.size(); i++)
1216 q_args[i] = q_args_[i].as_qreg(ctx);
1219 idx mapping_size = 1;
1220 std::vector<bool> mapped(q_args.size(),
false);
1221 for (idx i = 0; i < q_args.size(); i++) {
1222 if (q_args[i].size() > 1) {
1224 if (mapping_size == 1) {
1225 mapping_size = q_args[i].size();
1226 }
else if (mapping_size != q_args[i].size()) {
1227 std::cerr << loc_ <<
": Registers have different lengths\n";
1228 throw exception::SemanticError(
1229 "qpp::qasm::DeclaredGate::evaluate()");
1234 auto it = known_matrices.find(id_);
1235 if (it != known_matrices.end()) {
1237 auto circuit = ctx.get_circuit();
1238 auto mat = it->second(c_args);
1241 for (idx j = 0; j < mapping_size; j++) {
1243 std::vector<idx> mapped_args(q_args.size());
1244 for (idx i = 0; i < q_args.size(); i++) {
1245 mapped_args[i] = mapped[i] ? q_args[i][j] : q_args[i][0];
1249 if (ctx.ccontrolled()) {
1250 circuit->cCTRL_custom(mat, ctx.get_cctrls(), mapped_args,
1251 ctx.get_shift(), id_);
1253 circuit->gate_custom(mat, mapped_args, id_);
1259 for (idx i = 0; i < c_args.size(); i++) {
1260 ctx.set(gate->c_params_[i],
1261 std::unique_ptr<Value>(
new Number(c_args[i])));
1265 for (idx j = 0; j < mapping_size; j++) {
1267 for (idx i = 0; i < q_args.size(); i++) {
1268 ctx.set(gate->q_params_[i],
1269 std::unique_ptr<Value>(
new Qubit(
1270 mapped[i] ? q_args[i][j] : q_args[i][0])));
1274 for (
auto it = gate->body_.begin(); it != gate->body_.end();
1276 (*it)->evaluate(ctx);
1288 std::ostream& display(std::ostream& os)
const {
1290 if (c_args_.size() > 0) {
1292 for (
auto it = c_args_.begin(); it != c_args_.end(); it++) {
1293 os << (it == c_args_.begin() ?
"" :
",") << **it;
1298 for (
auto it = q_args_.begin(); it != q_args_.end(); it++) {
1299 os << (it == q_args_.begin() ?
"" :
",") << *it;
1311 class RealExpr final :
public Expr {
1321 RealExpr(Location loc,
double value) : Expr(loc), value_(value) {}
1326 double evaluate(Context& ctx)
const {
1334 std::ostream& display(std::ostream& os)
const {
1345 class IntExpr final :
public Expr {
1355 IntExpr(Location loc,
int value) : Expr(loc), value_(value) {}
1360 double evaluate(Context& ctx)
const {
1362 return (
double) value_;
1368 std::ostream& display(std::ostream& os)
const {
1379 class PiExpr final :
public Expr {
1386 PiExpr(Location loc) : Expr(loc) {}
1391 double evaluate(Context& ctx)
const {
1399 std::ostream& display(std::ostream& os)
const {
1410 class VarExpr final :
public Expr {
1420 VarExpr(Location loc, ident value) : Expr(loc), value_(value) {}
1425 double evaluate(Context& ctx)
const {
1426 auto val =
dynamic_cast<const Number*
>(ctx.lookup(value_, loc_));
1428 if (val ==
nullptr) {
1429 std::cerr << loc_ <<
": Identifier " << value_;
1430 std::cerr <<
" does not refer to a classical parameter\n";
1431 throw exception::ParseError(
"qpp::qasm::VarExpr::evaluate()");
1440 std::ostream& display(std::ostream& os)
const {
1451 class BExpr final :
public Expr {
1465 BExpr(Location loc, ExprPtr lexp, BinaryOp bop, ExprPtr rexp)
1466 : Expr(loc), lexp_(std::move(lexp)), bop_(bop), rexp_(std::move(rexp)) {
1472 double evaluate(Context& ctx)
const {
1473 double lval = lexp_->evaluate(ctx);
1474 double rval = rexp_->evaluate(ctx);
1477 case BinaryOp::Plus:
1479 case BinaryOp::Minus:
1481 case BinaryOp::Times:
1483 case BinaryOp::Divide:
1486 return pow(lval, rval);
1495 std::ostream& display(std::ostream& os)
const {
1496 os <<
"(" << *lexp_;
1498 case BinaryOp::Plus:
1501 case BinaryOp::Minus:
1504 case BinaryOp::Times:
1507 case BinaryOp::Divide:
1514 os << *rexp_ <<
")";
1524 class UExpr final :
public Expr {
1536 UExpr(Location loc, UnaryOp uop, ExprPtr exp)
1537 : Expr(loc), uop_(uop), exp_(std::move(exp)) {}
1542 double evaluate(Context& ctx)
const {
1543 double val = exp_->evaluate(ctx);
1568 std::ostream& display(std::ostream& os)
const {
1574 os <<
"sin(" << *exp_ <<
")";
1577 os <<
"cos(" << *exp_ <<
")";
1580 os <<
"tan(" << *exp_ <<
")";
1583 os <<
"ln(" << *exp_ <<
")";
1586 os <<
"sqrt(" << *exp_ <<
")";
1589 os <<
"exp(" << *exp_ <<
")";
Quantum++ main namespace.
Definition: circuits.h:35