1 /**
2 * This code is part of Qiskit.
3 *
4 * (C) Copyright IBM 2018, 2019.
5 *
6 * This code is licensed under the Apache License, Version 2.0. You may
7 * obtain a copy of this license in the LICENSE.txt file in the root directory
8 * of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9 *
10 * Any modifications or derivative works of this code must retain this
11 * copyright notice, and modified files need to carry a notice indicating
12 * that they have been altered from the originals.
13 */
14
15 #ifndef _aer_framework_json_hpp_
16 #define _aer_framework_json_hpp_
17
18 #include <complex>
19 #include <cstdint>
20 #include <fstream>
21 #include <iostream>
22 #include <map>
23 #include <vector>
24
25 #include <iostream>
26 #include <type_traits>
27
28 #include <nlohmann_json.hpp>
29 #include "framework/matrix.hpp"
30
31 namespace nl = nlohmann;
32 using json_t = nlohmann::json;
33
34 //============================================================================
35 // JSON Library helper functions
36 //============================================================================
37
38 namespace JSON {
39
40 /**
41 * Load a json_t from a file. If the file name is 'stdin' or '-' the json_t will
42 * be
43 * loaded from the standard input stream.
44 * @param name: file name to load.
45 * @returns: the loaded json.
46 */
47 json_t load(std::string name);
48
49 /**
50 * Check if a key exists in a json_t object.
51 * @param key: key name.
52 * @param js: the json_t to search for key.
53 * @returns: true if the key exists, false otherwise.
54 */
55 bool check_key(std::string key, const json_t &js);
56
57 /**
58 * Check if all keys exists in a json_t object.
59 * @param keys: vector of key names.
60 * @param js: the json_t to search for keys.
61 * @returns: true if all keys exists, false otherwise.
62 */
63 bool check_keys(std::vector<std::string> keys, const json_t &js);
64
65 /**
66 * Load a json_t object value into a variable if the key name exists.
67 * @param var: variable to store key value.
68 * @param key: key name.
69 * @param js: the json_t to search for key.
70 * @returns: true if the keys exists and val was set, false otherwise.
71 */
72 template <typename T> bool get_value(T &var, std::string key, const json_t &js);
73
74 } // end namespace JSON
75
76 //============================================================================
77 // JSON Conversion for complex STL types
78 //============================================================================
79
80 namespace std {
81
82 /**
83 * Convert a complex number to a json list z -> [real(z), imag(z)].
84 * @param js a json_t object to contain converted type.
85 * @param z a complex number to convert.
86 */
87 template <typename T> void to_json(json_t &js, const std::complex<T> &z);
88
89 /**
90 * Convert a JSON value to a complex number z. If the json value is a float
91 * it will be converted to a complex z = (val, 0.). If the json value is a
92 * length two list it will be converted to a complex z = (val[0], val[1]).
93 * @param js a json_t object to convert.
94 * @param z a complex number to contain result.
95 */
96 template <typename T> void from_json(const json_t &js, std::complex<T> &z);
97
98 /**
99 * Convert a complex vector to a json list
100 * v -> [ [real(v[0]), imag(v[0])], ...]
101 * @param js a json_t object to contain converted type.
102 * @param vec a complex vector to convert.
103 */
104 template <typename RealType>
105 void to_json(json_t &js, const std::vector<std::complex<RealType>> &vec);
106
107 /**
108 * Convert a JSON list to a complex vector. The input JSON value may be:
109 * - an object with complex pair values: {'00': [re, im], ... }
110 * - an object with real pair values: {'00': n, ... }
111 * - an list with complex values: [ [a0re, a0im], ...]
112 * - an list with real values: [a0, a1, ....]
113 * @param js a json_t object to convert.
114 * @param vec a complex vector to contain result.
115 */
116 template <typename RealType>
117 void from_json(const json_t &js, std::vector<std::complex<RealType>> &vec);
118
119 /**
120 * Convert a map with integer keys to a json. This converts the integer keys
121 * to strings in the resulting json object.
122 * @param js a json_t object to contain converted type.
123 * @param map a map to convert.
124 */
125 template <typename T1, typename T2>
126 void to_json(json_t &js, const std::map<int64_t, T1, T2> &map);
127
128 template <typename T1, typename T2>
129 void to_json(json_t &js, const std::map<uint64_t, T1, T2> &map);
130
131 } // end namespace std.
132
133 /**
134 * Convert a matrix to a json.
135 * @param js a json_t object to contain converted type.
136 * @param mat a matrix to convert.
137 */
138 template<class T>
139 void from_json(const json_t &js, matrix<T> &mat);
140 template<class T>
141 void to_json(json_t &js, const matrix<T> &mat);
142
143 /*******************************************************************************
144 *
145 * Implementations
146 *
147 ******************************************************************************/
148
149 //------------------------------------------------------------------------------
150 // JSON Helper Functions
151 //------------------------------------------------------------------------------
152
load(std::string name)153 json_t JSON::load(std::string name) {
154 if (name == "") {
155 json_t js;
156 return js; // Return empty node if no config file
157 }
158 json_t js;
159 if (name == "stdin" || name == "-") // Load from stdin
160 std::cin >> js;
161 else { // Load from file
162 std::ifstream ifile;
163 ifile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
164 try {
165 ifile.open(name);
166 } catch (std::exception &e) {
167 throw std::runtime_error(std::string("no such file or directory"));
168 }
169 ifile >> js;
170 }
171 return js;
172 }
173
check_key(std::string key,const json_t & js)174 bool JSON::check_key(std::string key, const json_t &js) {
175 // returns false if the value is 'null'
176 if (js.find(key) != js.end() && !js[key].is_null())
177 return true;
178 else
179 return false;
180 }
181
check_keys(std::vector<std::string> keys,const json_t & js)182 bool JSON::check_keys(std::vector<std::string> keys, const json_t &js) {
183 bool pass = true;
184 for (auto s : keys)
185 pass &= check_key(s, js);
186 return pass;
187 }
188
189 template <typename T>
get_value(T & var,std::string key,const json_t & js)190 bool JSON::get_value(T &var, std::string key, const json_t &js) {
191 if (check_key(key, js)) {
192 var = js[key].get<T>();
193 return true;
194 } else {
195 return false;
196 }
197 }
198
199 //------------------------------------------------------------------------------
200 // JSON Conversion
201 //------------------------------------------------------------------------------
202
203 template <typename RealType>
to_json(json_t & js,const std::complex<RealType> & z)204 void std::to_json(json_t &js, const std::complex<RealType> &z) {
205 js = std::pair<RealType, RealType>{z.real(), z.imag()};
206 }
207
208 template <typename RealType>
from_json(const json_t & js,std::complex<RealType> & z)209 void std::from_json(const json_t &js, std::complex<RealType> &z) {
210 if (js.is_number())
211 z = std::complex<RealType>{js.get<RealType>()};
212 else if (js.is_array() && js.size() == 2) {
213 z = std::complex<RealType>{js[0].get<RealType>(), js[1].get<RealType>()};
214 } else {
215 throw std::invalid_argument(
216 std::string("JSON: invalid complex number"));
217 }
218 }
219
220 template <typename RealType>
to_json(json_t & js,const std::vector<std::complex<RealType>> & vec)221 void std::to_json(json_t &js, const std::vector<std::complex<RealType>> &vec) {
222 std::vector<std::vector<RealType>> out;
223 for (auto &z : vec) {
224 out.push_back(std::vector<RealType>{real(z), imag(z)});
225 }
226 js = out;
227 }
228
229 template <typename RealType>
from_json(const json_t & js,std::vector<std::complex<RealType>> & vec)230 void std::from_json(const json_t &js, std::vector<std::complex<RealType>> &vec) {
231 std::vector<std::complex<RealType>> ret;
232 if (js.is_array()) {
233 for (auto &elt : js)
234 ret.push_back(elt);
235 vec = ret;
236 }
237 else {
238 throw std::invalid_argument(
239 std::string("JSON: invalid complex vector."));
240 }
241 }
242
243 // Int-key maps
244 template <typename T1, typename T2>
to_json(json_t & js,const std::map<int64_t,T1,T2> & map)245 void std::to_json(json_t &js, const std::map<int64_t, T1, T2> &map) {
246 js = json_t();
247 for (const auto &p : map) {
248 std::string key = std::to_string(p.first);
249 js[key] = p.second;
250 }
251 }
252
253 // Int-key maps
254 template <typename T1, typename T2>
to_json(json_t & js,const std::map<uint64_t,T1,T2> & map)255 void std::to_json(json_t &js, const std::map<uint64_t, T1, T2> &map) {
256 js = json_t();
257 for (const auto &p : map) {
258 std::string key = std::to_string(p.first);
259 js[key] = p.second;
260 }
261 }
262
263 // Matrices
264 //------------------------------------------------------------------------------
265 // Implementation: JSON Conversion
266 //------------------------------------------------------------------------------
267
to_json(json_t & js,const matrix<T> & mat)268 template <typename T> void to_json(json_t &js, const matrix<T> &mat) {
269 js = json_t();
270 size_t rows = mat.GetRows();
271 size_t cols = mat.GetColumns();
272 for (size_t r = 0; r < rows; r++) {
273 std::vector<T> mrow;
274 for (size_t c = 0; c < cols; c++)
275 mrow.push_back(mat(r, c));
276 js.push_back(mrow);
277 }
278 }
279
280
from_json(const json_t & js,matrix<T> & mat)281 template <typename T> void from_json(const json_t &js, matrix<T> &mat) {
282 // Check JSON is an array
283 if(!js.is_array()) {
284 throw std::invalid_argument(
285 std::string("JSON: invalid matrix (not array)."));
286 }
287 // Check JSON isn't empty
288 if(js.empty()) {
289 throw std::invalid_argument(
290 std::string("JSON: invalid matrix (empty array)."));
291 }
292 // check rows are all same length
293 bool rows_valid = js.is_array() && !js.empty();
294 // Check all entries of array are same size
295 size_t ncols = js[0].size();
296 size_t nrows = js.size();
297 for (auto &row : js)
298 rows_valid &= (row.is_array() && row.size() == ncols);
299 if(!rows_valid) {
300 throw std::invalid_argument(
301 std::string("JSON: invalid matrix (rows different sizes)."));
302 }
303 // Matrix looks ok, now we parse it
304 mat = matrix<T>(nrows, ncols);
305 for (size_t r = 0; r < nrows; r++)
306 for (size_t c = 0; c < ncols; c++)
307 mat(r, c) = js[r][c].get<T>();
308 }
309
310 //------------------------------------------------------------------------------
311 #endif
312