LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
poly_utils.cpp
浏览该文件的文档.
1#include <stdexcept>
10
11#include <algorithm>
12#include <cmath>
13#include <cstdint>
14#include <limits>
15#include <type_traits>
16#include <utility>
17
18namespace LMCAS {
19
20bool SymbolicPolyCoeff::operator==(const SymbolicPolyCoeff& other) const {
21 if (!val || !other.val) return false;
22 if (val == other.val) return true;
24 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
25 context.limits().max_ast_nodes, "polynomial.coefficient");
26 auto difference = SymbolicExpr::add(
27 val, SymbolicExpr::multiply(other.val, SymbolicExpr::number(-1)));
28 return detail::normalize_node(detail::node(difference), budget)->is_zero();
29}
30
31
32template <>
33Result<SymbolicPolyCoeff> extract_coeff_value<SymbolicPolyCoeff>(
34 const std::shared_ptr<SymbolicExpr>& coefficient) {
35 if (!coefficient || !detail::node(coefficient)) {
37 "Coefficient must have an expression", "polynomial.coefficient");
38 }
39 return SymbolicPolyCoeff(coefficient);
40}
41
42template <>
44 const std::shared_ptr<SymbolicExpr>& coefficient) try {
46 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
47 (context).limits().max_ast_nodes, "transform");
48 if (!coefficient || !detail::node(coefficient)) {
50 "Coefficient must have an expression", "polynomial.coefficient");
51 }
52 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(coefficient), transform_budget));
53 if (auto number = std::dynamic_pointer_cast<const NumberNode>(
54 LMCAS::detail::node(simplified))) {
55 if (std::holds_alternative<BigInt>(number->value())) {
56 return std::get<BigInt>(number->value());
57 }
58 if (std::holds_alternative<Rational>(number->value())) {
59 const Rational& value = std::get<Rational>(number->value());
60 if (value.is_integer()) return value.to_bigint();
61 }
62 }
64 "Coefficient is not an integer", "polynomial.coefficient");
65}
66catch (const CasError& error) {
67 return Result<BigInt>::failure(error);
68} catch (const std::bad_alloc&) {
69 return Result<BigInt>::failure(CasErrc::ResourceLimit, "allocation failed", "extract_coeff_value");
70} catch (const std::length_error& error) {
71 return Result<BigInt>::failure(CasErrc::ResourceLimit, error.what(), "extract_coeff_value");
72} catch (const std::exception& error) {
73 return Result<BigInt>::failure(CasErrc::InternalInvariant, error.what(), "extract_coeff_value");
74}
75
76template <>
78 const std::shared_ptr<SymbolicExpr>& coefficient) try {
80 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
81 (context).limits().max_ast_nodes, "transform");
82 if (!coefficient || !detail::node(coefficient)) {
84 "Coefficient must have an expression", "polynomial.coefficient");
85 }
86 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(coefficient), transform_budget));
87 if (auto number = std::dynamic_pointer_cast<const NumberNode>(
88 LMCAS::detail::node(simplified))) {
89 if (std::holds_alternative<Rational>(number->value())) {
90 return std::get<Rational>(number->value());
91 }
92 if (std::holds_alternative<BigInt>(number->value())) {
93 return Rational(std::get<BigInt>(number->value()));
94 }
95 }
96 if (simplified->is_one()) return Rational(1);
98 "Coefficient is not representable as a rational", "polynomial.coefficient");
99}
100catch (const CasError& error) {
101 return Result<Rational>::failure(error);
102} catch (const std::bad_alloc&) {
103 return Result<Rational>::failure(CasErrc::ResourceLimit, "allocation failed", "extract_coeff_value");
104} catch (const std::length_error& error) {
105 return Result<Rational>::failure(CasErrc::ResourceLimit, error.what(), "extract_coeff_value");
106} catch (const std::exception& error) {
107 return Result<Rational>::failure(CasErrc::InternalInvariant, error.what(), "extract_coeff_value");
108}
109
110bool contains(const SymbolicExpr& expression, const std::string& variable) {
112 LMCAS::detail::node(expression), variable);
113}
114
115template <typename T>
117 if (left.is_zero() || right.is_zero()) return true;
118 const auto max_terms = static_cast<std::size_t>(std::numeric_limits<int>::max());
119 return left.coeffs.size() <= max_terms &&
120 right.coeffs.size() - 1 <= max_terms - left.coeffs.size();
121}
122
123namespace {
124
125void checked_coefficient_count(std::size_t count, detail::RewriteBudget& budget) {
126 if (count > static_cast<std::size_t>(std::numeric_limits<int>::max())) {
128 "Polynomial coefficient storage limit exceeded", "polynomial.convert"};
129 }
130 auto terms = budget.context().require_expansion_terms(count, "polynomial.convert");
131 if (!terms) { throw terms.error(); }
132 budget.require_nodes(count);
133}
134
135std::size_t checked_product_count(std::size_t left, std::size_t right,
136 detail::RewriteBudget& budget) {
137 if (left == 0 || right == 0) return 0;
138 const auto maximum = static_cast<std::size_t>(std::numeric_limits<int>::max());
139 if (left > maximum || right - 1 > maximum - left) {
141 "Polynomial coefficient storage limit exceeded", "polynomial.convert"};
142 }
143 const auto count = left + right - 1;
144 checked_coefficient_count(count, budget);
145 return count;
146}
147
149 const detail::SymbolicNodePtr& node, detail::RewriteBudget& budget) {
150 auto step = budget.context().consume_steps(1, "polynomial.coefficient");
151 if (!step) { throw step.error(); }
152 return detail::normalize_node(node, budget);
153}
154
155template <typename Node>
158 detail::RewriteBudget& budget) {
161 std::vector<detail::SymbolicNodePtr>{left, right}), budget);
162}
163
165 detail::RewriteBudget& budget) {
166 while (!polynomial.coeffs.empty()) {
167 auto step = budget.context().consume_steps(1, "polynomial.coefficient");
168 if (!step) { throw step.error(); }
169 if (!detail::node(polynomial.coeffs.back().val)->is_zero()) break;
170 polynomial.coeffs.pop_back();
171 }
172}
173
176 detail::RewriteBudget& budget) {
177 const auto count = std::max(left.coeffs.size(), right.coeffs.size());
178 checked_coefficient_count(count, budget);
180 result.coeffs.reserve(count);
181 std::size_t nodes = 0;
182 for (std::size_t index = 0; index < count; ++index) {
183 detail::SymbolicNodePtr coefficient;
184 if (index < left.coeffs.size() && index < right.coeffs.size()) {
186 detail::node(left.coeffs[index].val), detail::node(right.coeffs[index].val), budget);
187 } else {
188 const auto& source = index < left.coeffs.size() ? left : right;
189 coefficient = detail::node(source.coeffs[index].val);
190 }
191 nodes = budget.append_size(nodes, budget.measure(coefficient));
192 result.coeffs.emplace_back(detail::make_expression_ptr(std::move(coefficient)));
193 }
194 trim_checked_coefficients(result, budget);
195 return result;
196}
197
200 detail::RewriteBudget& budget) {
201 const auto count = checked_product_count(left.coeffs.size(), right.coeffs.size(), budget);
203 result.coeffs.reserve(count);
204 std::size_t nodes = 0;
205 for (std::size_t degree = 0; degree < count; ++degree) {
206 detail::SymbolicNodePtr coefficient;
207 std::size_t coefficient_nodes = 0;
208 const auto first = degree < right.coeffs.size() ? 0 : degree - right.coeffs.size() + 1;
209 const auto last = std::min(degree, left.coeffs.size() - 1);
210 for (std::size_t index = first; index <= last; ++index) {
212 detail::node(left.coeffs[index].val),
213 detail::node(right.coeffs[degree - index].val), budget);
214 if (coefficient) {
215 coefficient = coefficient_arithmetic<AddNode>(coefficient, product, budget);
216 } else {
217 coefficient.swap(product);
218 }
219 coefficient_nodes = budget.measure(coefficient);
220 budget.append_size(nodes, coefficient_nodes);
221 }
222 nodes = budget.append_size(nodes, coefficient_nodes);
223 result.coeffs.emplace_back(detail::make_expression_ptr(std::move(coefficient)));
224 }
225 trim_checked_coefficients(result, budget);
226 return result;
227}
228
231 const auto& facts = detail::no_facts();
232 auto real_defined = detail::query_definedness(base, facts, Domain::Real, context);
233 if (!real_defined) { return Result<void>::failure(real_defined.error()); }
234 auto complex_defined = detail::query_definedness(base, facts, Domain::Complex, context);
235 if (!complex_defined) { return Result<void>::failure(complex_defined.error()); }
236 auto nonzero = detail::query_nonzero_value(base, facts, Domain::Real, context);
237 if (!nonzero) { return Result<void>::failure(nonzero.error()); }
238 if (real_defined.value() != Tribool::True ||
239 complex_defined.value() != Tribool::True || nonzero.value() != Tribool::True) {
241 "Zero power requires a defined nonzero base", "polynomial.convert");
242 }
243 return Result<void>::success();
244}
245
247 std::size_t base_count, int exponent, detail::RewriteBudget* budget) {
248 if (!budget || base_count == 0) { return Result<void>::success(); }
249 const auto degree = base_count - 1;
250 const auto maximum = static_cast<std::size_t>(std::numeric_limits<int>::max());
251 const auto count = static_cast<std::size_t>(exponent);
252 if (degree > (maximum - 1) / count) {
254 "Polynomial coefficient storage limit exceeded", "polynomial.convert");
255 }
256 checked_coefficient_count(degree * count + 1, *budget);
257 return Result<void>::success();
258}
259
260template <typename T>
262 const detail::SymbolicNodePtr& node, const std::string& variable,
263 detail::RewriteBudget* budget) {
264 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
265 if (budget) {
266 checked_coefficient_count(1, *budget);
267 auto coefficient = normalize_coefficient(node, *budget);
268 budget->append_size(0, budget->measure(coefficient));
269 Polynomial<T> result(variable);
270 result.coeffs.emplace_back(detail::make_expression_ptr(std::move(coefficient)));
271 trim_checked_coefficients(result, *budget);
272 return result;
273 }
274 }
275 auto coefficient = extract_coeff_value<T>(detail::make_expression_ptr(node));
276 if (!coefficient) { return Result<Polynomial<T>>::failure(coefficient.error()); }
277 return Polynomial<T>({std::move(coefficient.value())}, variable);
278}
279
280} // namespace
281
282template <typename T>
283Result<Polynomial<T>> symbolic_to_poly_recursive(
284 const std::shared_ptr<const SymbolicNode>& node,
285 const std::string& variable, ComputationContext* context, detail::RewriteBudget* budget);
286
287template <typename T>
289 const PowerNode& power, const std::string& variable,
291 detail::RewriteScope scope(budget);
292 BigInt exponent;
294 std::dynamic_pointer_cast<const NumberNode>(power.exponent()), exponent) ||
295 exponent.is_negative()) {
297 "Polynomial powers require nonnegative integer exponents", "polynomial.convert");
298 }
299 const auto bounded_exponent = exponent.try_to_int64();
300 if (!bounded_exponent || *bounded_exponent >= 1000) {
302 "Polynomial power expansion limit exceeded", "polynomial.convert");
303 }
304 const int exponent_value = static_cast<int>(*bounded_exponent);
305
306 Polynomial<T> result(variable);
307 if (budget) {
308 checked_coefficient_count(1, *budget);
310 }
311 result.coeffs.emplace_back(1);
312 if (exponent_value == 0) {
313 auto defined = check_zero_power_base(power.base(), *context);
314 if (!defined) { return Result<Polynomial<T>>::failure(defined.error()); }
315 return result;
316 }
317 const auto base = symbolic_to_poly_recursive<T>(power.base(), variable, context, budget);
318 if (!base) { return Result<Polynomial<T>>::failure(base.error()); }
319 auto count = check_power_coefficient_count(base.value().coeffs.size(), exponent_value, budget);
320 if (!count) { return Result<Polynomial<T>>::failure(count.error()); }
321 for (int index = 0; index < exponent_value; ++index) {
322 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
323 if (budget) {
324 result = multiply_checked_coefficients(result, base.value(), *budget);
325 continue;
326 }
327 }
328 if (!polynomial_product_fits(result, base.value())) {
330 "Polynomial coefficient storage limit exceeded", "polynomial.convert");
331 }
332 result = result * base.value();
333 }
334 return result;
335}
336
337template <typename T>
339 const AddNode& add, const std::string& variable,
341 detail::RewriteScope scope(budget);
342 Polynomial<T> result(variable);
343 for (const auto& operand : add.operands()) {
344 auto child = symbolic_to_poly_recursive<T>(operand, variable, context, budget);
345 if (!child) { return Result<Polynomial<T>>::failure(child.error()); }
346 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
347 if (budget) {
348 result = add_checked_coefficients(result, child.value(), *budget);
349 continue;
350 }
351 }
352 result = result + child.value();
353 }
354 return result;
355}
356
357template <typename T>
359 const MultiplyNode& multiply, const std::string& variable,
361 detail::RewriteScope scope(budget);
362 Polynomial<T> result(variable);
363 if (budget) {
364 checked_coefficient_count(1, *budget);
366 }
367 result.coeffs.emplace_back(1);
368 for (const auto& operand : multiply.operands()) {
369 auto child = symbolic_to_poly_recursive<T>(operand, variable, context, budget);
370 if (!child) { return Result<Polynomial<T>>::failure(child.error()); }
371 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
372 if (budget) {
373 result = multiply_checked_coefficients(result, child.value(), *budget);
374 continue;
375 }
376 }
377 if (!polynomial_product_fits(result, child.value())) {
379 "Polynomial coefficient storage limit exceeded", "polynomial.convert");
380 }
381 result = result * child.value();
382 }
383 return result;
384}
385
386template <typename T>
388 const std::shared_ptr<const SymbolicNode>& node,
389 const std::string& variable, ComputationContext* context, detail::RewriteBudget* budget) {
390 detail::RewriteScope scope(budget);
391 if (!node) {
393 "Expression node must not be null", "polynomial.convert");
394 }
395 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
396 BigInt exponent;
398 std::dynamic_pointer_cast<const NumberNode>(power->exponent()), exponent) &&
399 exponent.is_zero()) {
400 return symbolic_power_to_poly<T>(*power, variable, context, budget);
401 }
402 }
403 if (!expression_depends_on_variable(node, variable, budget)) {
404 return constant_to_poly<T>(node, variable, budget);
405 }
406
407 if (auto symbol = std::dynamic_pointer_cast<const VariableNode>(node)) {
408 if (!symbol->is_constant() && symbol->name() == variable) {
409 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
410 if (budget) {
411 checked_coefficient_count(2, *budget);
413 Polynomial<T> result(variable);
414 result.coeffs.reserve(2);
415 result.coeffs.emplace_back(0);
416 result.coeffs.emplace_back(1);
417 return result;
418 }
419 }
420 return Polynomial<T>({T(0), T(1)}, variable);
421 }
422 }
423
424 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
425 return symbolic_sum_to_poly<T>(*add, variable, context, budget);
426 }
427
428 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
429 return symbolic_product_to_poly<T>(*multiply, variable, context, budget);
430 }
431
432 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
433 return symbolic_power_to_poly<T>(*power, variable, context, budget);
434 }
435
437 "Expression is not a polynomial in the requested variable", "polynomial.convert");
438}
439
440template <typename T>
442 const std::shared_ptr<SymbolicExpr>& expression,
443 const std::string& variable) {
444 if (!expression || !LMCAS::detail::node(expression) || variable.empty()) {
446 "Expression and variable must not be empty", "polynomial.convert");
447 }
448 try {
451 } catch (const CasError& error) {
452 return Result<Polynomial<T>>::failure(error);
453 } catch (const std::bad_alloc&) {
455 "Polynomial allocation failed", "polynomial.convert");
456 } catch (const std::length_error& error) {
458 error.what(), "polynomial.convert");
459 }
460}
461
463 const SymbolicExpr& expression, const std::string& variable, ComputationContext& context) {
464 using ConversionResult = Result<Polynomial<SymbolicPolyCoeff>>;
465 if (!detail::node(expression) || variable.empty()) {
466 return ConversionResult::failure(CasErrc::InvalidArgument,
467 "Expression and variable must not be empty", "polynomial.convert");
468 }
469 try {
470 auto step = context.consume_steps(1, "polynomial.convert");
471 if (!step) return ConversionResult::failure(step.error());
472 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
473 context.limits().max_ast_nodes, "polynomial.convert");
474 budget.measure(detail::node(expression));
476 detail::node(expression), variable, &context, &budget);
477 } catch (const CasError& error) {
478 return ConversionResult::failure(error);
479 } catch (const std::bad_alloc&) {
480 return ConversionResult::failure(CasErrc::ResourceLimit,
481 "Polynomial allocation failed", "polynomial.convert");
482 } catch (const std::length_error& error) {
483 return ConversionResult::failure(CasErrc::ResourceLimit,
484 error.what(), "polynomial.convert");
485 }
486}
487
488template <typename T>
489LMCAS_API std::shared_ptr<SymbolicExpr> poly_to_symbolic(
490 const Polynomial<T>& polynomial) {
491 if (polynomial.is_zero()) return SymbolicExpr::number(0);
492
493 std::vector<std::shared_ptr<SymbolicExpr>> terms;
494 for (std::size_t degree = 0; degree < polynomial.coeffs.size(); ++degree) {
495 if (polynomial.coeffs[degree] == T(0)) continue;
496
497 std::shared_ptr<SymbolicExpr> coefficient;
498 if constexpr (std::is_same_v<T, SymbolicPolyCoeff>) {
499 coefficient = polynomial.coeffs[degree].val
500 ? polynomial.coeffs[degree].val
501 : SymbolicExpr::number(0);
502 } else {
503 coefficient = SymbolicExpr::number(polynomial.coeffs[degree]);
504 }
505
506 if (degree == 0) {
507 terms.push_back(coefficient);
508 continue;
509 }
510
511 auto variable = SymbolicExpr::variable(polynomial.variable_name);
512 auto variable_part = degree == 1
513 ? variable
514 : SymbolicExpr::power(
515 variable, SymbolicExpr::number(BigInt(static_cast<std::uint64_t>(degree))));
516 if (polynomial.coeffs[degree] == T(1)) {
517 terms.push_back(variable_part);
518 } else if (polynomial.coeffs[degree] == T(-1)) {
519 terms.push_back(SymbolicExpr::multiply(
520 SymbolicExpr::number(-1), variable_part));
521 } else {
522 terms.push_back(SymbolicExpr::multiply(coefficient, variable_part));
523 }
524 }
525
526 std::reverse(terms.begin(), terms.end());
527 if (terms.empty()) return SymbolicExpr::number(0);
528 auto result = terms.front();
529 for (std::size_t index = 1; index < terms.size(); ++index) {
530 result = SymbolicExpr::add(result, terms[index]);
531 }
532 return result;
533}
534
535template LMCAS_API Result<Polynomial<BigInt>> symbolic_to_poly<BigInt>(
536 const std::shared_ptr<SymbolicExpr>&, const std::string&);
537template LMCAS_API Result<Polynomial<Rational>> symbolic_to_poly<Rational>(
538 const std::shared_ptr<SymbolicExpr>&, const std::string&);
539template LMCAS_API Result<Polynomial<SymbolicPolyCoeff>> symbolic_to_poly<SymbolicPolyCoeff>(
540 const std::shared_ptr<SymbolicExpr>&, const std::string&);
541
542template LMCAS_API std::shared_ptr<SymbolicExpr> poly_to_symbolic<BigInt>(
543 const Polynomial<BigInt>&);
544template LMCAS_API std::shared_ptr<SymbolicExpr> poly_to_symbolic<Rational>(
545 const Polynomial<Rational>&);
546template LMCAS_API std::shared_ptr<SymbolicExpr> poly_to_symbolic<SymbolicPolyCoeff>(
548
549} // namespace LMCAS
加法节点,表示多个操作数的求和。
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
Result< void > require_expansion_terms(std::size_t amount, const std::string &operation={}) const
乘法节点,表示多个操作数的乘积。
一元多项式模板类
Polynomial(const std::string &var="x")
构造零多项式
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
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
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ComputationContext & context() const noexcept
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
void require_nodes(std::size_t nodes) const
std::size_t append_size(std::size_t current, std::size_t child)
#define LMCAS_API
void trim_checked_coefficients(Polynomial< SymbolicPolyCoeff > &polynomial, detail::RewriteBudget &budget)
void checked_coefficient_count(std::size_t count, detail::RewriteBudget &budget)
std::size_t checked_product_count(std::size_t left, std::size_t right, detail::RewriteBudget &budget)
Polynomial< SymbolicPolyCoeff > multiply_checked_coefficients(const Polynomial< SymbolicPolyCoeff > &left, const Polynomial< SymbolicPolyCoeff > &right, detail::RewriteBudget &budget)
Result< void > check_power_coefficient_count(std::size_t base_count, int exponent, detail::RewriteBudget *budget)
detail::SymbolicNodePtr normalize_coefficient(const detail::SymbolicNodePtr &node, detail::RewriteBudget &budget)
Result< void > check_zero_power_base(const detail::SymbolicNodePtr &base, ComputationContext &context)
Result< Polynomial< T > > constant_to_poly(const detail::SymbolicNodePtr &node, const std::string &variable, detail::RewriteBudget *budget)
detail::SymbolicNodePtr coefficient_arithmetic(const detail::SymbolicNodePtr &left, const detail::SymbolicNodePtr &right, detail::RewriteBudget &budget)
Polynomial< SymbolicPolyCoeff > add_checked_coefficients(const Polynomial< SymbolicPolyCoeff > &left, const Polynomial< SymbolicPolyCoeff > &right, detail::RewriteBudget &budget)
Result< Polynomial< SymbolicPolyCoeff > > symbolic_to_poly_checked(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const std::string & variable
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
const FactsQuery & no_facts() noexcept
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::size_t std::size_t ComputationContext & context
const std::string & variable
Result< Polynomial< T > > symbolic_power_to_poly(const PowerNode &power, const std::string &variable, ComputationContext *context, detail::RewriteBudget *budget)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
@ Complex
Complex numbers (default, least specific)
@ Rational
Rational numbers
@ Real
Real numbers
bool polynomial_product_fits(const Polynomial< T > &left, const Polynomial< T > &right)
Result< Polynomial< T > > symbolic_sum_to_poly(const AddNode &add, const std::string &variable, ComputationContext *context, detail::RewriteBudget *budget)
std::size_t normalization_check_arithmetic(detail::RewriteBudget *budget, std::size_t extra_nodes, const std::shared_ptr< const Nodes > &... children)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
@ True
Property definitely holds
Result< SymbolicPolyCoeff > extract_coeff_value< SymbolicPolyCoeff >(const std::shared_ptr< SymbolicExpr > &coefficient)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
Result< T > extract_coeff_value(const std::shared_ptr< SymbolicExpr > &coefficient)
精确提取系数;不支持的值返回错误,保持数值完整。
const ExprPtr & exponent
void normalization_check_children(detail::RewriteBudget *budget, std::size_t roots, const std::shared_ptr< const Nodes > &... children)
bool contains(const SymbolicExpr &expression, const std::string &variable)
const ExprPtr & right
const std::string const ExprPtr & value
Result< Polynomial< T > > symbolic_to_poly_recursive(const std::shared_ptr< const SymbolicNode > &node, const std::string &variable, ComputationContext *context, detail::RewriteBudget *budget)
Result< Polynomial< T > > symbolic_product_to_poly(const MultiplyNode &multiply, const std::string &variable, ComputationContext *context, detail::RewriteBudget *budget)
符号规范化访问器接口。
符号表达式与一元多项式的转换。
符号多项式算法使用的表达式系数。
std::shared_ptr< SymbolicExpr > val
内部 AST 定义。