LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
expr_serialization_reader.cpp
浏览该文件的文档.
1#include "lmcas_export.hpp"
3
4#include <charconv>
5#include <limits>
6#include <new>
7#include <stdexcept>
8#include <string_view>
9#include <utility>
10
11namespace LMCAS {
12namespace {
13using namespace serialization_detail;
14
15class Reader {
16public:
17 Reader(const std::string& source, ComputationContext& context)
18 : source_(source), context_(context), position_(kHeader.size()) {}
19
21 auto result = node();
22 if (position_ != source_.size()) invalid("trailing serialized expression data");
23 return result;
24 }
25
26private:
27 std::size_t nodes_ = 0;
28 [[noreturn]] void invalid(const char* message) const {
29 throw CasError{CasErrc::ParseError, message, kDecode};
30 }
31 std::size_t read_length() {
32 std::size_t length = 0;
33 while (position_ < source_.size() && source_[position_] >= '0' &&
34 source_[position_] <= '9') {
35 const auto digit = static_cast<std::size_t>(source_[position_++] - '0');
36 if (length > (std::numeric_limits<std::size_t>::max() - digit) / 10)
37 invalid("serialized expression length overflow");
38 length = length * 10 + digit;
39 }
40 return length;
41 }
42 std::string_view field() {
43 check(context_.consume_steps(1, kDecode));
44 const auto begin = position_;
45 const auto length = read_length();
46 if (begin == position_) {
47 invalid("invalid serialized expression length");
48 }
49 if (position_ == source_.size()) {
50 invalid("invalid serialized expression length");
51 }
52 if (source_[position_++] != ':') {
53 invalid("invalid serialized expression length");
54 }
55 if (position_ - begin > 2 && source_[begin] == '0') {
56 invalid("invalid serialized expression length");
57 }
58 if (length >= source_.size() - position_) {
59 invalid("truncated serialized expression field");
60 }
61 if (source_[position_ + length] != ',') {
62 invalid("truncated serialized expression field");
63 }
64 auto result = std::string_view(source_).substr(position_, length);
65 position_ += length + 1;
66 return result;
67 }
68 std::size_t unsigned_field() {
69 const auto text = field();
70 std::size_t result = 0;
71 auto parsed = std::from_chars(text.data(), text.data() + text.size(), result);
72 if (text.empty() || (text.size() > 1 && text[0] == '0') ||
73 parsed.ec != std::errc{} || parsed.ptr != text.data() + text.size())
74 invalid("invalid serialized expression integer");
75 return result;
76 }
77 std::size_t count() {
78 auto n = unsigned_field();
79 if (n > source_.size() - position_)
80 invalid("invalid serialized expression count");
81 if (n > context_.limits().max_ast_nodes)
82 throw CasError{CasErrc::ResourceLimit, "AST node budget exhausted", kDecode};
83 return n;
84 }
85 bool flag() {
86 auto text = field();
87 if (text == "0") return false;
88 if (text == "1") return true;
89 invalid("invalid serialized expression flag");
90 }
91 template <typename Enum, std::size_t N>
92 Enum choice(const std::array<std::string_view, N>& names) {
93 auto text = field();
94 for (std::size_t i = 0; i < names.size(); ++i)
95 if (text == names[i]) return static_cast<Enum>(i);
96 invalid("invalid serialized expression operator");
97 }
98 void check_integer_digits(std::string_view text, std::size_t first) const {
99 for (std::size_t i = first; i < text.size(); ++i)
100 if (text[i] < '0' || text[i] > '9') invalid("invalid serialized expression integer");
101 }
102 BigInt integer() {
103 auto text = field();
104 if (text.empty()) {
105 invalid("invalid serialized expression integer");
106 }
107 std::size_t first = text.front() == '-' ? 1 : 0;
108 if (first == text.size()) {
109 invalid("invalid serialized expression integer");
110 }
111 if (text.size() - first > 1 && text[first] == '0') {
112 invalid("invalid serialized expression integer");
113 }
114 check_integer_digits(text, first);
115 if (first != 0 && text.substr(first) == "0") {
116 invalid("invalid serialized expression integer");
117 }
118 // Decimal length gives an inexpensive lower bound before allocating BigInt.
119 if (text.size() - first > context_.limits().max_integer_bits / 3 + 1) {
120 throw CasError{CasErrc::ResourceLimit, "integer bit budget exceeded", kDecode};
121 }
122 BigInt result{std::string(text)};
123 check(context_.require_integer_bits(result.bit_length(), kDecode));
124 return result;
125 }
126 Rational rational() {
127 auto numerator = integer();
128 auto denominator = integer();
129 if (denominator <= BigInt(0)) invalid("invalid serialized expression denominator");
130 return Rational(numerator, denominator);
131 }
132 std::vector<NodePtr> nodes() {
133 auto n = count();
134 std::vector<NodePtr> result;
135 result.reserve(n);
136 for (std::size_t i = 0; i < n; ++i) result.push_back(node());
137 return result;
138 }
140 auto rows = unsigned_field(), cols = unsigned_field();
141 if (!rows || !cols || rows > std::numeric_limits<std::size_t>::max() / cols ||
142 rows * cols > source_.size() - position_)
143 invalid("invalid matrix dimensions");
144 if (rows * cols > context_.limits().max_ast_nodes)
145 throw CasError{CasErrc::ResourceLimit, "AST node budget exhausted", kDecode};
147 elements.reserve(rows * cols);
148 for (std::size_t i = 0; i < rows * cols; ++i) elements.push_back(node());
149 return detail::make_node<MatrixNode>(rows, cols, std::move(elements));
150 }
152 auto count_branches = count();
153 std::vector<PiecewiseNode::Branch> branches;
154 branches.reserve(count_branches);
155 for (std::size_t i = 0; i < count_branches; ++i) {
156 auto expression = node();
157 branches.push_back({expression, node()});
158 }
159 auto has_default = flag();
160 return detail::make_node<PiecewiseNode>(std::move(branches), has_default ? node() : nullptr);
161 }
163 auto dimensions = count();
164 DimensionSignature::Exponents exponents;
165 for (std::size_t i = 0; i < dimensions; ++i) {
166 auto name = std::string(field());
167 auto exponent = rational();
168 if (name.empty() || exponent.is_zero() ||
169 !exponents.emplace(std::move(name), std::move(exponent)).second)
170 invalid("invalid dimension exponent");
171 }
172 auto dimension = DimensionSignature(std::move(exponents));
173 return detail::make_node<QuantityNode>(node(), std::move(dimension), Rational(1), "");
174 }
176 auto name = std::string(field());
177 auto index = unsigned_field(), size = count();
178 std::vector<Rational> coefficients;
179 coefficients.reserve(size);
180 for (std::size_t i = 0; i < size; ++i) coefficients.push_back(rational());
181 if (coefficients.size() < 2 || coefficients.back().is_zero() ||
182 index >= coefficients.size() - 1) invalid("invalid root identity");
183 detail::ExactRootId id{Polynomial<Rational>(coefficients), index};
184 return detail::make_node<RootOfNode>(std::move(id), std::move(name));
185 }
188 if (nodes_ == std::numeric_limits<std::size_t>::max()) {
189 throw CasError{CasErrc::ResourceLimit, "AST node count overflow", kDecode};
190 }
191 check(context_.require_ast_nodes(++nodes_, kDecode));
192 auto kind = field();
193 if (kind == "integer") return detail::make_node<NumberNode>(integer());
194 if (kind == "rational") return detail::make_node<NumberNode>(rational());
195 if (kind == "symbol") {
196 auto name = field();
197 return detail::make_node<VariableNode>(std::string(name));
198 }
199 if (kind == "constant") {
200 auto name = field();
201 if (name != "pi" && name != "π" && name != "e" && name != "phi")
202 throw CasError{CasErrc::UnsupportedExpression, "unknown mathematical constant", kDecode};
203 return detail::make_node<VariableNode>(std::string(name), true);
204 }
205 if (kind == "add") return detail::make_node<AddNode>(nodes());
206 if (kind == "multiply") return detail::make_node<MultiplyNode>(nodes());
207 return compound_node(kind);
208 }
209 NodePtr compound_node(std::string_view kind) {
210 if (kind == "power") { auto base = node(); return detail::make_node<PowerNode>(base, node()); }
211 if (kind == "complex") { auto real = node(); return detail::make_node<ComplexNode>(real, node()); }
212 if (kind == "function") {
215 }
216 if (kind == "call") {
217 auto name = field();
218 if (name.empty()) invalid("empty function name");
220 }
221 if (kind == "matrix") return matrix();
222 if (kind == "relation") {
224 auto lhs = node(); return detail::make_node<RelationalNode>(lhs, node(), op);
225 }
226 if (kind == "logic") {
228 auto lhs = node();
229 return detail::make_node<LogicalNode>(lhs, op == LogicalNode::Op::Not ? nullptr : node(), op);
230 }
231 if (kind == "piecewise") return piecewise();
232 return extended_node(kind);
233 }
234 NodePtr extended_node(std::string_view kind) {
235 if (kind == "sum" || kind == "product") {
236 auto name = std::string(field());
237 auto lower = node(), upper = node(), body = node();
238 if (kind == "sum") return detail::make_node<SummationNode>(body, std::move(name), lower, upper);
239 return detail::make_node<ProductNode>(body, std::move(name), lower, upper);
240 }
241 if (kind == "transform") {
243 auto name = std::string(field());
244 auto target = node(), body = node();
245 return detail::make_node<TransformNode>(type, body, std::move(name), target);
246 }
247 if (kind == "quantifier") {
249 auto name = std::string(field());
250 auto domain = node(), predicate = node();
251 return detail::make_node<QuantifierNode>(type, std::move(name), domain, predicate);
252 }
253 if (kind == "set_builder") {
254 auto name = std::string(field());
255 auto domain = node(), predicate = node();
256 return detail::make_node<SetBuilderNode>(std::move(name), domain, predicate);
257 }
258 if (kind == "set") return detail::make_node<FiniteSetNode>(nodes());
259 if (kind == "interval") {
260 auto lower_closed = flag(), upper_closed = flag();
261 auto lower = node();
263 }
264 if (kind == "membership") {
266 }
267 if (kind == "quantity") return quantity();
268 if (kind == "integral") {
269 auto name = std::string(field());
270 auto bounded = flag();
272 if (bounded) { lower = node(); upper = node(); }
273 return detail::make_node<IntegralNode>(node(), std::move(name), lower, upper);
274 }
275 if (kind == "limit") {
276 auto name = std::string(field());
278 auto point = node();
279 return detail::make_node<LimitNode>(node(), std::move(name), point, direction);
280 }
281 if (kind == "root_of") return root_of();
282 throw CasError{CasErrc::UnsupportedExpression, "unknown expression kind", kDecode};
283 }
284
285 const std::string& source_;
287 std::size_t position_;
288};
289} // namespace
290
291LMCAS_API ExpressionResult parse_serialized_expr(const std::string& source,
293 auto input = context.require_input_bytes(source.size(), kDecode);
294 if (!input) return ExpressionResult::failure(input.error());
295 if (source.compare(0, kHeader.size(), kHeader.data(), kHeader.size()) != 0)
297 "unknown serialized expression version", kDecode);
298 try {
299 return detail::make_expression_ptr(Reader(source, context).finish());
300 } catch (const CasError& error) {
301 return ExpressionResult::failure(error);
302 } catch (const std::bad_alloc&) {
304 "expression parse allocation failed", kDecode);
305 } catch (const std::exception& error) {
306 return ExpressionResult::failure(CasErrc::ParseError, error.what(), kDecode);
307 }
308}
309
310LMCAS_API ExpressionResult parse_serialized_expr(const std::string& source) {
312 return parse_serialized_expr(source, context);
313}
314} // namespace LMCAS
@ Not
一元逻辑非,right 为 nullptr。
std::vector< std::shared_ptr< const SymbolicNode > > DenseStorage
稠密存储,按行优先展开。
一元多项式模板类
static Result failure(CasErrc code, std::string message, std::string operation={})
void check_integer_digits(std::string_view text, std::size_t first) const
#define LMCAS_API
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
std::shared_ptr< const Node > make_node(Args &&... args)
constexpr std::array< std::string_view, 36 > kFunctions
constexpr std::array< std::string_view, 5 > kTransforms
constexpr std::array< std::string_view, 3 > kDirections
constexpr std::array< std::string_view, 6 > kRelations
constexpr std::array< std::string_view, 2 > kQuantifiers
constexpr std::array< std::string_view, 4 > kLogic
const std::string const LimitExprPtr & point
const ExprPtr & element
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & lower
const std::string const LimitExprPtr LimitDirection direction
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
const ExprPtr RelationOp op
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr bool lower_closed
const ExprPtr & exponent
std::size_t std::size_t depth
const NumberDomainSet & domain
const ExprPtr & target
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr bool bool upper_closed
const ExprPtr & denominator
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name