libqasm
library for handling cQASM files
cqasm-v1-values.cpp
Go to the documentation of this file.
1 
5 #include "cqasm-error.hpp"
7 #include "cqasm-v1-values.hpp"
8 #include "cqasm-v1-types.hpp"
9 #include "cqasm-v1-semantic.hpp"
10 
11 namespace cqasm {
12 namespace v1 {
13 namespace values {
14 
17 
25 Value promote(const Value &value, const types::Type &type) {
26 
27  // If the types match exactly, just return the original value.
28  if (types::type_check(type, type_of(value))) {
29  return value;
30  }
31 
32  // Handle promotion rules. If a promotion succeeds, the promoted value is
33  // put in retval.
34  Value retval{};
35 
36  // Integers promote to real.
37  if (type->as_real()) {
38  if (auto const_int = value->as_const_int()) {
39  retval = tree::make<values::ConstReal>(const_int->value);
40  }
41  }
42 
43  // Integers and reals promote to complex.
44  if (type->as_complex()) {
45  if (auto const_int = value->as_const_int()) {
46  retval = tree::make<values::ConstComplex>(const_int->value);
47  } else if (auto const_real = value->as_const_real()) {
48  retval = tree::make<values::ConstComplex>(const_real->value);
49  }
50  }
51 
52  // Real matrix promotes to complex matrix.
53  if (auto mat_type = type->as_complex_matrix()) {
54  if (auto const_real_matrix = value->as_const_real_matrix()) {
55  // Match matrix size. Negative sizes in the type mean unconstrained.
56  if ((tree::signed_size_t) const_real_matrix->value.size_rows() == mat_type->num_rows || mat_type->num_rows < 0) {
57  if ((tree::signed_size_t) const_real_matrix->value.size_cols() == mat_type->num_cols || mat_type->num_cols < 0) {
58  // Convert double to complex.
59  const size_t rows = const_real_matrix->value.size_rows();
60  const size_t cols = const_real_matrix->value.size_cols();
61  primitives::CMatrix complex_mat_value(rows, cols);
62  for (size_t row = 1; row <= rows; row++) {
63  for (size_t col = 1; col <= cols; col++) {
64  complex_mat_value.at(row, col) = const_real_matrix->value.at(row, col);
65  }
66  }
67  retval = tree::make<values::ConstComplexMatrix>(complex_mat_value);
68  }
69  }
70 
71  // NOTE: DEPRECATED BEHAVIOR, FOR BACKWARDS COMPATIBILITY ONLY
72  // If the expected matrix has a defined size and is square, and
73  // the real matrix is a vector with the 2 * 4**n entries, we
74  // interpret it as an old-style cqasm unitary matrix, from
75  // before cqasm knew what complex numbers (or multidimensional
76  // matrices) were.
77  if (retval.empty() && mat_type->num_rows == mat_type->num_cols && mat_type->num_rows > 0) {
78  const size_t size = mat_type->num_rows;
79  const size_t num_elements = 2 * size * size;
80  if (const_real_matrix->value.size_rows() == 1 && const_real_matrix->value.size_cols() == num_elements) {
81  primitives::CMatrix complex_mat_value(size, size);
82  size_t index = 1;
83  for (size_t row = 1; row <= size; row++) {
84  for (size_t col = 1; col <= size; col++) {
85  double re = const_real_matrix->value.at(1, index++);
86  double im = const_real_matrix->value.at(1, index++);
87  complex_mat_value.at(row, col) = std::complex<double>(re, im);
88  }
89  }
90  retval = tree::make<values::ConstComplexMatrix>(complex_mat_value);
91  }
92  }
93  }
94  }
95 
96  // If a promotion rule was successful, copy the source location annotation
97  // from the old value to the new one.
98  if (!retval.empty()) {
99  retval->copy_annotation<parser::SourceLocation>(*value);
100  }
101 
102  return retval;
103 }
104 
108 types::Type type_of(const Value &value) {
109  if (value->as_const_bool()) {
110  return tree::make<types::Bool>(false);
111  } else if (value->as_const_axis()) {
112  return tree::make<types::Axis>(false);
113  } else if (value->as_const_int()) {
114  return tree::make<types::Int>(false);
115  } else if (value->as_const_real()) {
116  return tree::make<types::Real>(false);
117  } else if (value->as_const_complex()) {
118  return tree::make<types::Complex>(false);
119  } else if (auto const_real_matrix = value->as_const_real_matrix()) {
120  return tree::make<types::RealMatrix>(
121  const_real_matrix->value.size_rows(),
122  const_real_matrix->value.size_cols(),
123  false);
124  } else if (auto const_complex_matrix = value->as_const_complex_matrix()) {
125  return tree::make<types::ComplexMatrix>(
126  const_complex_matrix->value.size_rows(),
127  const_complex_matrix->value.size_cols(),
128  false);
129  } else if (value->as_const_string()) {
130  return tree::make<types::String>(false);
131  } else if (value->as_const_json()) {
132  return tree::make<types::Json>(false);
133  } else if (value->as_qubit_refs()) {
134  return tree::make<types::Qubit>(true);
135  } else if (value->as_bit_refs()) {
136  return tree::make<types::Bool>(true);
137  } else if (auto fn = value->as_function()) {
138  return fn->return_type;
139  } else if (auto var = value->as_variable_ref()) {
140  return var->variable->typ;
141  } else {
142  throw std::runtime_error("unknown type!");
143  }
144 }
145 
149 types::Types types_of(const Values &values) {
150  types::Types types;
151  for (auto value : values) {
152  types.add(type_of(value));
153  }
154  return types;
155 }
156 
161 void check_const(const Value &value) {
162  if (!value->as_constant()) {
163  throw error::AnalysisError("dynamic values are not supported here", &*value);
164  }
165 }
166 
171 void check_const(const Values &values) {
172  for (auto value : values) {
173  check_const(value);
174  }
175 }
176 
180 std::ostream &operator<<(std::ostream &os, const Value &value) {
181  if (value.empty()) {
182  os << "NULL";
183  } else {
184  os << *value;
185  }
186  return os;
187 }
188 
192 std::ostream &operator<<(std::ostream &os, const Values &values) {
193  os << "[";
194  bool first = true;
195  for (const auto &value : values) {
196  if (first) {
197  first = false;
198  } else {
199  os << ", ";
200  }
201  if (value.empty()) {
202  os << "NULL";
203  } else {
204  os << *value;
205  }
206  }
207  os << "]";
208  return os;
209 }
210 
211 } // namespace values
212 } // namespace v1
213 } // namespace cqasm
Two-dimensional matrix of some kind of type.
types::Types types_of(const Values &values)
Returns the types of the given values.
std::ostream & operator<<(std::ostream &os, const Value &value)
Stream << overload for a single value.
types::Type type_of(const Value &value)
Returns the type of the given value.
Toplevel namespace with entry points for the new API.
Defines classes representing the values (collective name for constants, references, and dynamically evaluated expressions) available within cQASM&#39;s type system, as well as some utility functions.
Source location annotation object, containing source file line numbers etc.
tree::Any< Node > Values
Zero or more cQASM values.
Defines the types for the cQASM semantic tree, based on the classes from cqasm::tree.
Contains helper classes and objects for the lexer and parser generated by flex/bison, as well as the entry points for invoking the parser directly, in case you don&#39;t need semantic analysis.
Value promote(const Value &value, const types::Type &type)
Type-checks and (if necessary) promotes the given value to the given type.
Namespace for the "new" cQASM 1.x API.
NodeType
Enumeration of all node types.
Contains custom exception objects used by libqasm.
tree::One< Node > Value
A cQASM value, either known at compile-time or an expression for something only known at runtime...
tree::One< TypeBase > Type
A cQASM type.
bool type_check(const Type &expected, const Type &actual)
Returns whether the actual type matches the constraints of the expected type.
void check_const(const Value &value)
Throws an AnalysisError if the given value is not a constant, i.e.
tree::Any< TypeBase > Types
Zero or more cQASM types.
::tree::signed_size_t signed_size_t
Definition: cqasm-tree.hpp:17
Defines the types of values available within cQASM&#39;s type system, as well as some utility functions...
NodeType
Enumeration of all node types.
Exception used for analysis errors.
Definition: cqasm-error.hpp:27
T at(size_t row, size_t col) const
Returns the value at the given position.