LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
expr_serialization.cpp
浏览该文件的文档.
1#include "lmcas_export.hpp"
3
4#include <array>
5#include <charconv>
6#include <limits>
7#include <new>
8#include <stdexcept>
9#include <string_view>
10#include <utility>
11
12namespace LMCAS {
13namespace {
14using namespace serialization_detail;
15
16
18public:
20
21 std::string finish(const NodePtr& root) {
22 emit(root);
23 return std::move(output_);
24 }
25
26 void visit(const NumberNode& n) override {
27 const auto& value = n.value();
28 if (const auto* integer = std::get_if<BigInt>(&value)) {
29 put("integer");
31 } else {
32 put("rational");
33 put_rational(std::get<Rational>(value));
34 }
35 }
36 void visit(const VariableNode& n) override {
37 put(n.is_constant() ? "constant" : "symbol"); put(n.name());
38 }
39 void visit(const AddNode& n) override { put("add"); emit_list(n.operands()); }
40 void visit(const MultiplyNode& n) override { put("multiply"); emit_list(n.operands()); }
41 void visit(const PowerNode& n) override {
42 put("power"); emit(n.base()); emit(n.exponent());
43 }
44 void visit(const FunctionNode& n) override {
45 put("function"); put(enum_name(n.type(), kFunctions, kEncode));
47 }
48 void visit(const UninterpretedFunctionNode& n) override {
49 put("call"); put(n.name()); emit_list(n.arguments());
50 }
51 void visit(const MatrixNode& n) override {
52 put("matrix"); put_size(n.rows()); put_size(n.cols());
53 for (std::size_t r = 0; r < n.rows(); ++r)
54 for (std::size_t c = 0; c < n.cols(); ++c)
55 emit(n.get(r, c));
56 }
57 void visit(const RelationalNode& n) override {
58 put("relation"); put(enum_name(n.op(), kRelations, kEncode));
59 emit(n.left()); emit(n.right());
60 }
61 void visit(const LogicalNode& n) override {
62 put("logic"); put(enum_name(n.op(), kLogic, kEncode));
63 emit(n.left());
64 if (n.op() != LogicalNode::Op::Not) emit(n.right());
65 }
66 void visit(const PiecewiseNode& n) override {
67 put("piecewise"); put_size(n.branches().size());
68 for (const auto& branch : n.branches()) {
69 emit(branch.expression); emit(branch.condition);
70 }
71 put(n.default_expr() ? "1" : "0");
72 if (n.default_expr()) emit(n.default_expr());
73 }
74 void visit(const SummationNode& n) override {
75 put("sum"); put(n.index_var()); emit(n.lower_bound());
76 emit(n.upper_bound()); emit(n.body());
77 }
78 void visit(const ProductNode& n) override {
79 put("product"); put(n.index_var()); emit(n.lower_bound());
80 emit(n.upper_bound()); emit(n.body());
81 }
82 void visit(const TransformNode& n) override {
83 put("transform"); put(enum_name(n.transform_type(), kTransforms, kEncode));
84 put(n.source_var()); emit(n.target()); emit(n.body());
85 }
86 void visit(const QuantifierNode& n) override {
87 put("quantifier"); put(enum_name(n.quantifier_type(), kQuantifiers, kEncode));
88 put(n.bound_var()); emit(n.domain()); emit(n.predicate());
89 }
90 void visit(const SetBuilderNode& n) override {
91 put("set_builder"); put(n.element_var()); emit(n.domain()); emit(n.predicate());
92 }
93 void visit(const FiniteSetNode& n) override { put("set"); emit_list(n.elements()); }
94 void visit(const IntervalNode& n) override {
95 put("interval"); put(n.lower_closed() ? "1" : "0");
96 put(n.upper_closed() ? "1" : "0"); emit(n.lower()); emit(n.upper());
97 }
98 void visit(const MembershipNode& n) override {
99 put("membership"); emit(n.element()); emit(n.set());
100 }
101 void visit(const QuantityNode& n) override {
102 put("quantity"); put_size(n.dimension().exponents().size());
103 for (const auto& [name, exponent] : n.dimension().exponents()) {
105 }
106 // A quantity's physical value is its displayed value multiplied by its exact scale.
107 emit(base_value(n));
108 }
109 void visit(const ComplexNode& n) override {
110 put("complex"); emit(n.real()); emit(n.imag());
111 }
112 void visit(const IntegralNode& n) override {
113 put("integral"); put(n.variable()); put(n.is_definite() ? "1" : "0");
114 if (n.is_definite()) { emit(n.lower()); emit(n.upper()); }
115 emit(n.body());
116 }
117 void visit(const LimitNode& n) override {
118 put("limit"); put(n.variable()); put(enum_name(n.direction(), kDirections, kEncode));
119 emit(n.point()); emit(n.body());
120 }
121 void visit(const RootOfNode& n) override {
122 put("root_of"); put(n.variable()); put_size(n.index());
124 for (const auto& coefficient : n.exact_id().polynomial.coeffs)
125 put_rational(coefficient);
126 }
127
128private:
129 bool needs_scale(const QuantityNode& n, const NodePtr& base) {
130 if (n.scale_to_base() != Rational(1)) return true;
131 if (dynamic_cast<const MultiplyNode*>(base.get())) return true;
132 const auto* number = dynamic_cast<const NumberNode*>(base.get());
133 return number && std::holds_alternative<Rational>(number->value());
134 }
135 bool collect_exact_factors(const std::vector<NodePtr>& factors,
136 Rational& coefficient, std::vector<NodePtr>& remaining) {
137 bool exact_factor = false;
138 for (const auto& factor : factors) {
139 const auto* number = dynamic_cast<const NumberNode*>(factor.get());
140 if (!number) {
141 remaining.push_back(factor);
142 continue;
143 }
144 const Rational value = std::holds_alternative<BigInt>(number->value())
145 ? Rational(std::get<BigInt>(number->value()))
146 : std::get<Rational>(number->value());
147 check(context_.require_integer_bits(value.get_numerator().bit_length(), kEncode));
148 check(context_.require_integer_bits(value.get_denominator().bit_length(), kEncode));
149 coefficient = coefficient * value;
150 check(context_.require_integer_bits(coefficient.get_numerator().bit_length(), kEncode));
151 check(context_.require_integer_bits(coefficient.get_denominator().bit_length(), kEncode));
152 exact_factor = true;
153 }
154 return exact_factor;
155 }
157 NodePtr base = n.value();
158 if (!needs_scale(n, base)) return base;
159 Rational coefficient = n.scale_to_base();
160 check(context_.require_integer_bits(coefficient.get_numerator().bit_length(), kEncode));
161 check(context_.require_integer_bits(coefficient.get_denominator().bit_length(), kEncode));
162 std::vector<NodePtr> factors;
163 if (const auto* product = dynamic_cast<const MultiplyNode*>(base.get()))
164 factors.assign(product->operands().begin(), product->operands().end());
165 else
166 factors.push_back(base);
167 std::vector<NodePtr> remaining;
168 remaining.reserve(factors.size() + 1);
169 const bool exact_factor = collect_exact_factors(factors, coefficient, remaining);
170 return scaled_value(base, coefficient, remaining, exact_factor);
171 }
172 NodePtr scaled_value(const NodePtr& base, const Rational& coefficient,
173 std::vector<NodePtr>& remaining, bool exact_factor) {
174 if (exact_factor || coefficient != Rational(1)) {
175 if (coefficient != Rational(1) || remaining.empty()) {
176 remaining.push_back(coefficient.is_integer()
177 ? SymbolicFactory::create_number(coefficient.to_bigint())
178 : SymbolicFactory::create_number(coefficient));
179 }
180 return remaining.size() == 1 ? remaining.front()
181 : SymbolicFactory::create_multiply(std::move(remaining));
182 }
183 return base;
184 }
185 void put(std::string_view field) {
186 check(context_.consume_steps(1, kEncode));
187 char digits[std::numeric_limits<std::size_t>::digits10 + 2];
188 auto end = std::to_chars(digits, digits + sizeof(digits), field.size()).ptr;
189 const auto width = static_cast<std::size_t>(end - digits);
190 const auto extra = width + 2;
191 if (field.size() > context_.limits().max_input_bytes ||
192 output_.size() > context_.limits().max_input_bytes - field.size() ||
193 extra > context_.limits().max_input_bytes - field.size() - output_.size()) {
194 throw CasError{CasErrc::ResourceLimit, "serialized expression byte limit exceeded", kEncode};
195 }
196 output_.append(digits, width);
197 output_ += ':';
198 output_.append(field.data(), field.size());
199 output_ += ',';
200 }
201 void put_size(std::size_t value) {
202 char digits[std::numeric_limits<std::size_t>::digits10 + 2];
203 auto end = std::to_chars(digits, digits + sizeof(digits), value).ptr;
204 put(std::string_view(digits, static_cast<std::size_t>(end - digits)));
205 }
206 void put_integer(const BigInt& value) {
207 check(context_.require_integer_bits(value.bit_length(), kEncode));
208 put(value.to_string());
209 }
210 void put_rational(const Rational& value) {
211 put_integer(value.get_numerator());
212 put_integer(value.get_denominator());
213 }
214 template <typename Children>
215 void emit_list(const Children& children) {
216 put_size(children.size());
217 for (const auto& child : children) emit(child);
218 }
219 void emit(const NodePtr& node) {
221 if (!node) throw CasError{CasErrc::InvalidArgument, "null expression node", kEncode};
222 try {
223 node->accept(*this);
224 } catch (const std::runtime_error& error) {
225 if (std::string_view(error.what()) == "AST traversal depth limit exceeded")
226 throw CasError{CasErrc::ResourceLimit, error.what(), kEncode};
227 throw;
228 }
229 }
230
232 std::string output_;
233};
234
235
236} // namespace
237
238LMCAS_API Result<std::string> serialize_expr(const ExprPtr& expression,
240 auto step = context.consume_steps(1, kEncode);
241 if (!step) return Result<std::string>::failure(step.error());
242 if (!expression || !detail::node(expression))
244 "expression cannot be null", kEncode);
245 try {
246 return Writer(context).finish(detail::node(expression));
247 } catch (const CasError& error) {
248 return Result<std::string>::failure(error);
249 } catch (const std::bad_alloc&) {
251 "expression serialization allocation failed", kEncode);
252 } catch (const std::exception& error) {
254 error.what(), kEncode);
255 }
256}
257
258LMCAS_API Result<std::string> serialize_expr(const ExprPtr& expression) {
260 return serialize_expr(expression, context);
261}
262
263
264} // namespace LMCAS
加法节点,表示多个操作数的求和。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
复数节点,表示 real + imag * i。
const std::shared_ptr< const SymbolicNode > & real() const noexcept
const std::shared_ptr< const SymbolicNode > & imag() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & elements() const noexcept
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & arguments() const noexcept
const auto & body() const noexcept
const auto & upper() const noexcept
const auto & lower() const noexcept
bool is_definite() const noexcept
const std::string & variable() const noexcept
bool upper_closed() const noexcept
bool lower_closed() const noexcept
const auto & lower() const noexcept
const auto & upper() const noexcept
const std::string & variable() const noexcept
const auto & point() const noexcept
const auto & body() const noexcept
LimitDirection direction() const noexcept
@ Not
一元逻辑非,right 为 nullptr。
Op op() const noexcept
const std::shared_ptr< const SymbolicNode > & right() const noexcept
const std::shared_ptr< const SymbolicNode > & left() const noexcept
矩阵节点,支持稠密和稀疏两种存储方式。
size_t cols() const noexcept
size_t rows() const noexcept
std::shared_ptr< const SymbolicNode > get(size_t r, size_t c) const
获取指定位置的矩阵元素。
const auto & set() const noexcept
const auto & element() const noexcept
乘法节点,表示多个操作数的乘积。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
const std::variant< BigInt, Rational > & value() const noexcept
分段函数节点,表示条件分支表达式.
const std::shared_ptr< const SymbolicNode > & default_expr() const noexcept
const std::vector< Branch > & branches() const noexcept
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
连乘节点,表示符号有限/无限连乘 prod_{k=a}^{b} f(k).
const std::shared_ptr< const SymbolicNode > & lower_bound() const noexcept
const std::shared_ptr< const SymbolicNode > & upper_bound() const noexcept
const std::shared_ptr< const SymbolicNode > & body() const noexcept
const std::string & index_var() const noexcept
Type quantifier_type() const noexcept
const std::string & bound_var() const noexcept
const std::shared_ptr< const SymbolicNode > & predicate() const noexcept
const std::shared_ptr< const SymbolicNode > & domain() const noexcept
const auto & value() const noexcept
const Rational & scale_to_base() const noexcept
const auto & dimension() const noexcept
Op op() const noexcept
const std::shared_ptr< const SymbolicNode > & right() const noexcept
const std::shared_ptr< const SymbolicNode > & left() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
const std::string & variable() const noexcept
std::size_t index() const noexcept
const LMCAS::detail::ExactRootId & exact_id() const noexcept
const std::shared_ptr< const SymbolicNode > & domain() const noexcept
const std::shared_ptr< const SymbolicNode > & predicate() const noexcept
const std::string & element_var() const noexcept
求和节点,表示符号有限/无限求和 sum_{k=a}^{b} f(k).
const std::shared_ptr< const SymbolicNode > & lower_bound() const noexcept
const std::shared_ptr< const SymbolicNode > & body() const noexcept
const std::string & index_var() const noexcept
const std::shared_ptr< const SymbolicNode > & upper_bound() const noexcept
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
static std::shared_ptr< const SymbolicNode > create_number(const ::LMCAS::BigInt &v)
积分变换节点,表示 Laplace,Fourier,Z 变换及其逆变换.
const std::string & source_var() const noexcept
TransformType transform_type() const noexcept
const std::shared_ptr< const SymbolicNode > & target() const noexcept
const std::shared_ptr< const SymbolicNode > & body() const noexcept
const auto & arguments() const noexcept
const std::string & name() const noexcept
变量节点,表示一个符号变量。
bool is_constant() const noexcept
const std::string & name() const noexcept
bool needs_scale(const QuantityNode &n, const NodePtr &base)
NodePtr scaled_value(const NodePtr &base, const Rational &coefficient, std::vector< NodePtr > &remaining, bool exact_factor)
void visit(const UninterpretedFunctionNode &n) override
bool collect_exact_factors(const std::vector< NodePtr > &factors, Rational &coefficient, std::vector< NodePtr > &remaining)
#define LMCAS_API
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::string_view enum_name(Enum value, const std::array< std::string_view, N > &names, const char *operation)
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
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
const VectorField const VectorField & c
const ExprPtr & exponent
std::size_t std::size_t depth
std::shared_ptr< SymbolicExpr > ExprPtr
const std::string const ExprPtr & value
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
Polynomial< Rational > polynomial