19bool SymbolicExpr::is_number()
const {
20 return impl_->root->is_number();
23bool SymbolicExpr::get_number_value_is_zero()
const {
24 return impl_->root->is_zero();
27bool SymbolicExpr::is_big_int()
const {
28 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
30 std::holds_alternative<BigInt>(number_node->value());
33bool SymbolicExpr::is_rational()
const {
34 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
36 std::holds_alternative<Rational>(number_node->value());
39bool SymbolicExpr::is_int()
const {
40 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
41 if (!number_node)
return false;
42 if (std::holds_alternative<BigInt>(number_node->value()))
return true;
43 return std::get<Rational>(number_node->value()).is_integer();
46std::variant<int, BigInt, Rational> SymbolicExpr::get_number()
const {
47 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
49 throw std::runtime_error(
"Expression is not a number");
51 if (std::holds_alternative<BigInt>(number_node->value())) {
52 return std::get<BigInt>(number_node->value());
54 return std::get<Rational>(number_node->value());
57int SymbolicExpr::get_int()
const {
59 throw std::runtime_error(
"Expression is not an integer");
61 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
62 if (std::holds_alternative<BigInt>(number_node->value())) {
63 auto value = std::get<BigInt>(number_node->value()).try_to_int64();
64 if (!
value || *
value < std::numeric_limits<int>::min() ||
65 *
value > std::numeric_limits<int>::max()) {
66 throw std::out_of_range(
"integer value does not fit in int");
68 return static_cast<int>(*value);
70 auto value = std::get<Rational>(number_node->value()).to_bigint().try_to_int64();
71 if (!
value || *
value < std::numeric_limits<int>::min() ||
72 *
value > std::numeric_limits<int>::max()) {
73 throw std::out_of_range(
"integer value does not fit in int");
75 return static_cast<int>(*value);
78BigInt SymbolicExpr::get_big_int()
const {
79 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
81 !std::holds_alternative<BigInt>(number_node->value())) {
82 throw std::runtime_error(
"Expression is not a BigInt");
84 return std::get<BigInt>(number_node->value());
87Rational SymbolicExpr::get_rational()
const {
88 auto number_node = std::dynamic_pointer_cast<const NumberNode>(impl_->root);
90 !std::holds_alternative<Rational>(number_node->value())) {
91 throw std::runtime_error(
"Expression is not a Rational");
93 return std::get<Rational>(number_node->value());
96Rational SymbolicExpr::convert_rational()
const {
97 if (is_rational())
return get_rational();
98 if (is_big_int())
return Rational(get_big_int());
103int SymbolicExpr::compare(
const std::shared_ptr<SymbolicExpr>& other)
const {
110std::string SymbolicExpr::to_string()
const {
111 PrintVisitor printer;
113 impl_->root->accept(printer);
114 return printer.get_result();
119lmmc_real_t SymbolicExpr::to_numeric()
const {
122 throw std::runtime_error(
"numeric evaluation failed: " + evaluated.error().message);
124 return static_cast<lmmc_real_t
>(evaluated.value().
value);
127bool SymbolicExpr::is_zero()
const {
128 if (!impl_->root)
return false;
129 if (
auto num = std::dynamic_pointer_cast<const NumberNode>(impl_->root)) {
130 if (
const auto*
integer = std::get_if<BigInt>(&
num->value())) {
133 if (
const auto*
rational = std::get_if<Rational>(&
num->value())) {
140bool SymbolicExpr::is_one()
const {
141 if (!impl_->root)
return false;
142 if (
auto num = std::dynamic_pointer_cast<const NumberNode>(impl_->root)) {
143 if (
const auto*
integer = std::get_if<BigInt>(&
num->value())) {
146 if (
const auto*
rational = std::get_if<Rational>(&
num->value())) {
154std::shared_ptr<SymbolicExpr> SymbolicExpr::simplify_trig()
const {
157 context.limits().max_ast_nodes,
"simplify_trig");
161 static const LMCAS::RewriteEngine engine = [] {
162 LMCAS::RewriteEngine configured;
163 using namespace LMCAS;
167 auto sinx = SymbolicExpr::sin(x);
168 auto cosx = SymbolicExpr::cos(x);
169 auto n2 = SymbolicExpr::number(2);
170 auto sin2 = SymbolicExpr::power(sinx, n2);
171 auto cos2 = SymbolicExpr::power(cosx, n2);
173 auto pat1 = SymbolicExpr::add(sin2, cos2);
174 configured.add_rule(Rule(*pat1, *SymbolicExpr::number(1), {
"x"}));
176 auto pat2 = SymbolicExpr::add(cos2, sin2);
177 configured.add_rule(Rule(*pat2, *SymbolicExpr::number(1), {
"x"}));
179 auto two_x = SymbolicExpr::multiply(n2, x);
180 auto sin2x = SymbolicExpr::sin(two_x);
181 auto two_sin_cos = SymbolicExpr::multiply(n2,
182 SymbolicExpr::multiply(sinx, cosx));
183 configured.add_rule(Rule(*sin2x, *two_sin_cos, {
"x"}));
185 auto cos2x = SymbolicExpr::cos(two_x);
186 auto cos2_sub_sin2 = SymbolicExpr::add(cos2,
187 SymbolicExpr::multiply(sin2, SymbolicExpr::number(-1)));
188 configured.add_rule(Rule(*cos2x, *cos2_sub_sin2, {
"x"}));
192 auto rewritten = engine.apply_checked(*res,
context);
193 if (!rewritten)
return res;
194 auto simplified = std::move(rewritten.value());
210 node->accept(visitor);
229 node->accept(visitor);
239 "LMCAS.differentiate"};
243 node->accept(visitor);
std::shared_ptr< const SymbolicNode > get_result() const
获取求导结果。
std::shared_ptr< const SymbolicNode > get_result() const
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
std::shared_ptr< const SymbolicNode > get_result() const
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
模式匹配引擎 Matcher 与重写规则系统 RewriteEngine。
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr expand_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const std::string & variable
const std::string const SymbolicNodePtr & replacement
RewriteBudget const FactsQuery Domain domain
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
RewriteBudget const FactsQuery & facts
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > num(int value)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
SymbolicExpr wildcard(const std::string &name)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Rational
Rational numbers
const std::string const ExprPtr & value
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
ExprResult rational(const Rational &value)
detail::SymbolicNodePtr substitute_free(const detail::SymbolicNodePtr &expression, const std::string &variable, const detail::SymbolicNodePtr &replacement, detail::RewriteBudget *budget)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.