io.h
1 /* Copyright (C) 2020 IBM Corp.
2  * This program is Licensed under the Apache License, Version 2.0
3  * (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://www.apache.org/licenses/LICENSE-2.0
6  * Unless required by applicable law or agreed to in writing, software
7  * distributed under the License is distributed on an "AS IS" BASIS,
8  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9  * See the License for the specific language governing permissions and
10  * limitations under the License. See accompanying LICENSE file.
11  */
12 
13 #ifndef HELIB_IO_H
14 #define HELIB_IO_H
23 #include <complex>
24 
25 #include <json.hpp>
26 using json = ::nlohmann::json;
27 
28 #include <NTL/vec_long.h>
29 #include <NTL/xdouble.h>
30 
31 #include <helib/exceptions.h>
32 #include <helib/JsonWrapper.h>
33 #include <helib/version.h>
34 
35 // For our convenience, this helps us.
36 namespace NTL {
37 void to_json(json& j, const NTL::xdouble& num);
38 void from_json(const json& j, NTL::xdouble& num);
39 
40 void to_json(json& j, const NTL::ZZ& num);
41 void from_json(const json& j, NTL::ZZ& num);
42 
43 void to_json(json& j, const NTL::Vec<long>& vec);
44 void from_json(const json& j, NTL::Vec<long>& vec);
45 
46 void to_json(json& j, const NTL::ZZX& poly);
47 void from_json(const json& j, NTL::ZZX& poly);
48 } // namespace NTL
49 
50 namespace std {
51 template <typename T>
52 inline void to_json(json& j, const std::complex<T>& num)
53 {
54  // e.g. 'stdev': {'real': 10.1, 'imag': 9.3 }
55  j = {num.real(), num.imag()};
56 }
57 
58 // Permissive JSON to std::complex<T> function. I accepts single numbers,
59 // or a JSON object containing a real and/or imag part.
60 // Fails if the json value is not convertible to the type T.
61 template <typename T>
62 inline void from_json(const json& j, std::complex<T>& num)
63 {
64  num.real(0);
65  num.imag(0);
66 
67  if (j.is_number()) {
68  // Set only the imaginary part
69  num.real(j.get<T>());
70  return;
71  } else {
72  if (j.size() > 2) {
73  throw helib::IOError("Bad complex JSON serialization. Expected a maximum "
74  "of 2 elements, recieved " +
75  std::to_string(j.size()));
76  }
77  if (j.size() == 0) {
78  return;
79  }
80  num.real(j[0].get<T>());
81  if (j.size() == 2) {
82  num.imag(j[1].get<T>());
83  }
84  }
85 }
86 } // namespace std
87 
88 namespace helib {
89 
90 class Context;
91 
92 inline const std::string_view jsonSerializationVersion = "0.0.1";
93 
94 inline JsonWrapper wrap(const json& j)
95 {
96  return JsonWrapper(std::make_any<json>(j));
97 }
98 
99 inline json unwrap(const JsonWrapper& jwrap)
100 {
101  try {
102  return std::any_cast<json>(jwrap.getJSONobj());
103  } catch (const std::bad_any_cast& e) {
104  throw LogicError(std::string("Cannot unwrap wrapper. Bad cast ") +
105  e.what());
106  }
107 }
108 
109 template <typename T>
110 inline std::vector<T> readVectorFromJSON(const json::array_t& j)
111 {
112  std::vector<T> v;
113  v.reserve(j.size());
114 
115  for (const auto& e : j) {
116  v.emplace_back(T::readFromJSON(wrap(e)));
117  }
118 
119  return v;
120 }
121 
122 template <typename T, typename... TArgs>
123 inline std::vector<T> readVectorFromJSON(const json::array_t& j,
124  const TArgs&... args)
125 {
126  std::vector<T> v;
127  v.reserve(j.size());
128 
129  for (const auto& e : j) {
130  v.emplace_back(T::readFromJSON(wrap(e), args...));
131  }
132 
133  return v;
134 }
135 
136 template <typename T>
137 inline void readVectorFromJSON(const json::array_t& j,
138  std::vector<T>& v,
139  T& init)
140 {
141  std::vector<json> jvec = j;
142 
143  v.resize(jvec.size(), init); // Make space in vector
144 
145  for (std::size_t i = 0; i < jvec.size(); i++) {
146  v[i].readJSON(wrap(jvec[i]));
147  }
148 }
149 
150 template <typename T>
151 inline json writeVectorToJSON(const std::vector<T>& ts)
152 {
153  std::vector<json> js;
154  for (const auto& t : ts) {
155  js.emplace_back(unwrap(t.writeToJSON()));
156  }
157  return js;
158 }
159 
160 template <typename T>
161 static inline json toTypedJson(const json& tc)
162 {
163  return {{"type", T::typeName},
164  {"HElibVersion", version::asString},
165  {"serializationVersion", jsonSerializationVersion},
166  {"content", tc}};
167 }
168 
169 template <typename T>
170 static inline json fromTypedJson(const json& j)
171 {
172  std::string obj_ser_ver = j.at("serializationVersion").get<std::string>();
173  if (obj_ser_ver != jsonSerializationVersion) {
174  std::stringstream sstr;
175  sstr << "Serialization version mismatch. Expected: "
176  << jsonSerializationVersion << " actual: " << obj_ser_ver;
177  throw IOError(sstr.str());
178  }
179 
180  std::string obj_helib_ver = j.at("HElibVersion").get<std::string>();
181  if (obj_helib_ver != version::asString) {
182  std::stringstream sstr;
183  sstr << "HElib version mismatch. Expected: " << version::asString
184  << " actual: " << obj_helib_ver;
185  throw IOError(sstr.str());
186  }
187 
188  std::string obj_ty = j.at("type").get<std::string>();
189  if (obj_ty != T::typeName) {
190  std::stringstream fmt;
191  fmt << "Type mismatch deserializing json object."
192  << " Expected: " << T::typeName << " actual: " << obj_ty;
193  throw IOError(fmt.str());
194  }
195  return j.at("content");
196 }
197 
198 template <typename T, typename TCALL>
199 inline T executeRedirectJsonError(const TCALL& f)
200 {
201  try {
202  return f();
203  } catch (const nlohmann::detail::exception& e) {
204  throw IOError(std::string("Error with JSON IO. ") + e.what());
205  }
206 }
207 
208 } // namespace helib
209 
210 #endif // HELIB_IO_H
Inherits from Exception and std::runtime_error.
Definition: exceptions.h:123
Inherits from Exception and std::logic_error.
Definition: exceptions.h:68
Definition: io.cpp:18
void to_json(json &j, const NTL::xdouble &num)
Definition: io.cpp:20
void from_json(const json &j, NTL::xdouble &num)
Definition: io.cpp:26
Definition: apiAttributes.h:21
std::vector< T > readVectorFromJSON(const json::array_t &j)
Definition: io.h:110
json unwrap(const JsonWrapper &jwrap)
Definition: io.h:99
T executeRedirectJsonError(const TCALL &f)
Definition: io.h:199
const std::string_view jsonSerializationVersion
Definition: io.h:92
JsonWrapper wrap(const json &j)
Definition: io.h:94
json writeVectorToJSON(const std::vector< T > &ts)
Definition: io.h:151
Definition: io.h:50
void to_json(json &j, const std::complex< T > &num)
Definition: io.h:52
void from_json(const json &j, std::complex< T > &num)
Definition: io.h:62
Definition: JsonWrapper.h:9
const std::any & getJSONobj() const
Definition: JsonWrapper.h:13
static constexpr auto asString
The string representation of this version of HElib.
Definition: version.in.h:44