LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transform_support.cpp
浏览该文件的文档.
2#include <cmath>
3
5
6bool te_depends_on(const std::shared_ptr<SymbolicExpr>& expression,
7 const std::string& variable) {
8 return expression &&
10 LMCAS::detail::node(expression), variable);
11}
12
13Result<void> te_validate_expr_vars(const std::shared_ptr<SymbolicExpr>& expr,
14 const std::string& input_var,
15 const std::string& output_var,
17 const std::string& operation) {
18 auto step = context.consume_steps(1, operation);
19 if (!step) return step;
20 if (!expr || !LMCAS::detail::node(expr)) {
22 "transform expression cannot be null",
23 operation);
24 }
25 if (input_var.empty() || output_var.empty()) {
27 "transform variable names cannot be empty",
28 operation);
29 }
30 if (input_var == output_var) {
32 "input and output variables must be distinct",
33 operation);
34 }
35 return Result<void>::success();
36}
38 const std::shared_ptr<const SymbolicNode>& node) {
40}
41
43 std::shared_ptr<SymbolicExpr> expr,
44 const std::string& operation) {
45 if (!expr || !LMCAS::detail::node(expr)) {
48 "transform construction produced a null expression",
49 operation);
50 }
51
55 "transform is outside the current evaluated support domain",
56 operation);
57 }
58
61 EvaluatedTransform{std::move(expr), {}, {}},
63}
64
65std::shared_ptr<SymbolicExpr> te_gt_condition(
66 const std::shared_ptr<SymbolicExpr>& lhs,
67 const std::shared_ptr<SymbolicExpr>& rhs) {
68 if (!lhs || !LMCAS::detail::node(lhs) || !rhs || !LMCAS::detail::node(rhs)) return nullptr;
71}
72
73bool te_is_zero(const std::shared_ptr<SymbolicExpr>& e) {
74 return e && LMCAS::detail::node(e) && e->is_zero();
75}
76std::optional<Rational> te_number_value(
77 const std::shared_ptr<const SymbolicNode>& node) {
78 const auto number = std::dynamic_pointer_cast<const NumberNode>(node);
79 if (!number) return std::nullopt;
80 if (std::holds_alternative<BigInt>(number->value())) {
81 return Rational(std::get<BigInt>(number->value()));
82 }
83 return std::get<Rational>(number->value());
84}
85BigInt te_factorial(const BigInt& n, ComputationContext& context) {
86 auto result = BigInt::factorial_checked(n, context);
87 if (!result) throw result.error();
88 return std::move(result.value());
89}
90std::pair<std::shared_ptr<SymbolicExpr>,std::shared_ptr<SymbolicExpr>>
91te_split_coeff(const std::shared_ptr<SymbolicExpr>& e, const std::string& v) {
92 if (!e || !LMCAS::detail::node(e) || !te_depends_on(e, v)) return {e ? e : SymbolicExpr::number(1), SymbolicExpr::number(1)};
93 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(e));
94 if (!mul) return {SymbolicExpr::number(1), e};
95 std::vector<std::shared_ptr<const SymbolicNode>> cp, vp;
96 for (auto& op : mul->operands()) {
97 if (expression_depends_on_variable(op, v)) vp.push_back(op); else cp.push_back(op);
98 }
99 if (cp.empty()) return {SymbolicExpr::number(1), e};
100 if (vp.empty()) return {e, SymbolicExpr::number(1)};
101 auto c = (cp.size()==1) ? LMCAS::detail::make_expression_ptr(cp[0])
103 auto b = (vp.size()==1) ? LMCAS::detail::make_expression_ptr(vp[0])
105 return {c, b};
106}
107
108std::shared_ptr<SymbolicExpr> te_linear_coefficient(
109 const std::shared_ptr<const SymbolicNode>& argument, const std::string& variable) {
110 auto symbol = std::dynamic_pointer_cast<const VariableNode>(argument);
111 if (symbol && !symbol->is_constant() && symbol->name() == variable) {
113 }
114 auto product = std::dynamic_pointer_cast<const MultiplyNode>(argument);
115 if (!product || product->operands().size() != 2) {
116 return nullptr;
117 }
118 for (std::size_t i = 0; i < 2; ++i) {
119 symbol = std::dynamic_pointer_cast<const VariableNode>(product->operands()[i]);
120 const auto& other = product->operands()[1 - i];
121 if (!symbol || symbol->is_constant() || symbol->name() != variable) continue;
122 if (expression_depends_on_variable(other, variable)) continue;
123 return detail::make_expression_ptr(other);
124 }
125 return nullptr;
126}
127
128namespace {
129
131 const std::shared_ptr<const SymbolicNode>& expression,
132 const std::string& variable) {
133 const auto power =
134 std::dynamic_pointer_cast<const PowerNode>(expression);
135 if (!power) return false;
136 const auto base =
137 std::dynamic_pointer_cast<const VariableNode>(power->base());
138 return base && !base->is_constant() && base->name() == variable &&
139 exact_small_integer_node(power->exponent(), 2, 2).has_value();
140}
141
142std::optional<Rational> te_atomic_gaussian_rate(
143 const std::shared_ptr<const SymbolicNode>& argument,
144 const std::string& variable) {
145 auto parts = te_split_coeff(
147 const auto coefficient = te_number_value(detail::node(parts.first));
148 if (!coefficient ||
150 !(*coefficient < Rational(0))) {
151 return std::nullopt;
152 }
153 return -*coefficient;
154}
155
157 const std::shared_ptr<const SymbolicNode>& factor,
158 const std::string& variable, Rational& coefficient,
159 bool& has_variable_square) {
160 if (const auto number = te_number_value(factor)) {
161 coefficient = coefficient * *number;
162 return true;
163 }
164 if (!te_is_variable_square(factor, variable)) return false;
165 has_variable_square = true;
166 return true;
167}
168
169std::optional<Rational> te_gaussian_product_rate(
170 const MultiplyNode& product, const std::string& variable) {
171 Rational coefficient(1);
172 bool has_variable_square = false;
173 for (const auto& factor : product.operands()) {
175 factor, variable, coefficient, has_variable_square)) {
176 return std::nullopt;
177 }
178 }
179 return has_variable_square && coefficient < Rational(0)
180 ? std::optional<Rational>(-coefficient)
181 : std::nullopt;
182}
183}
184
185std::optional<Rational> te_match_pure_gaussian(
186 const std::shared_ptr<SymbolicExpr>& expression,
187 const std::string& variable) {
188 if (!expression || !detail::node(expression)) return std::nullopt;
189 const auto function = std::dynamic_pointer_cast<const FunctionNode>(
190 detail::node(expression));
191 if (!function || function->type() != FunctionNode::FuncType::Exp ||
192 function->arguments().empty()) {
193 return std::nullopt;
194 }
195 const auto product = std::dynamic_pointer_cast<const MultiplyNode>(
196 function->arguments()[0]);
197 if (!product) return std::nullopt;
198
199 return te_gaussian_product_rate(*product, variable);
200}
201
202std::optional<GaussianMatch> te_match_scaled_gaussian(
203 const std::shared_ptr<SymbolicExpr>& expression,
204 const std::string& variable) {
205 auto parts = te_split_coeff(expression, variable);
206 const auto coefficient = te_number_value(detail::node(parts.first));
207 if (!coefficient) {
208 return std::nullopt;
209 }
210 const auto function = std::dynamic_pointer_cast<const FunctionNode>(
211 detail::node(parts.second));
212 if (!function || function->type() != FunctionNode::FuncType::Exp ||
213 function->arguments().size() != 1) {
214 return std::nullopt;
215 }
216 const auto rate =
217 te_atomic_gaussian_rate(function->arguments()[0], variable);
218 if (!rate) return std::nullopt;
219 return GaussianMatch{std::move(parts.first), *rate};
220}
221
222bool te_is_trig(const std::shared_ptr<SymbolicExpr>& expression,
223 const std::string& variable, bool& is_sin,
224 std::shared_ptr<SymbolicExpr>& frequency) {
225 if (!expression || !detail::node(expression)) {
226 return false;
227 }
228 auto function = std::dynamic_pointer_cast<const FunctionNode>(detail::node(expression));
229 if (!function || function->arguments().empty()) {
230 return false;
231 }
232 if (function->type() != FunctionNode::FuncType::Sin &&
234 return false;
235 }
236 is_sin = function->type() == FunctionNode::FuncType::Sin;
237 frequency = te_linear_coefficient(function->arguments()[0], variable);
238 return frequency != nullptr;
239}
240
241}
乘法节点,表示多个操作数的乘积。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static std::shared_ptr< const SymbolicNode > create_number(const ::LMCAS::BigInt &v)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
bool contains_node_type(const SymbolicNodePtr &root)
std::shared_ptr< const Node > make_node(Args &&... args)
bool te_accumulate_gaussian_factor(const std::shared_ptr< const SymbolicNode > &factor, const std::string &variable, Rational &coefficient, bool &has_variable_square)
std::optional< Rational > te_gaussian_product_rate(const MultiplyNode &product, const std::string &variable)
std::optional< Rational > te_atomic_gaussian_rate(const std::shared_ptr< const SymbolicNode > &argument, const std::string &variable)
bool te_is_variable_square(const std::shared_ptr< const SymbolicNode > &expression, const std::string &variable)
Result< void > te_validate_expr_vars(const std::shared_ptr< SymbolicExpr > &expression, const std::string &input_var, const std::string &output_var, ComputationContext &context, const std::string &operation)
bool te_is_trig(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable, bool &is_sin, std::shared_ptr< SymbolicExpr > &frequency)
std::pair< std::shared_ptr< SymbolicExpr >, std::shared_ptr< SymbolicExpr > > te_split_coeff(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
std::shared_ptr< SymbolicExpr > te_linear_coefficient(const std::shared_ptr< const SymbolicNode > &argument, const std::string &variable)
bool te_is_zero(const std::shared_ptr< SymbolicExpr > &expression)
std::shared_ptr< SymbolicExpr > te_gt_condition(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs)
bool te_contains_transform(const std::shared_ptr< const SymbolicNode > &node)
bool te_depends_on(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
TransformEngineResult te_wrap_transform_result(std::shared_ptr< SymbolicExpr > expression, const std::string &operation)
std::optional< GaussianMatch > te_match_scaled_gaussian(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
BigInt te_factorial(const BigInt &n, ComputationContext &context)
std::optional< Rational > te_match_pure_gaussian(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
std::optional< Rational > te_number_value(const std::shared_ptr< const SymbolicNode > &node)
const std::string & variable
ExprResult e()
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::string & v
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const VectorField const VectorField & c
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
const MultiPoly & b
const ExprPtr RelationOp op
std::optional< int > exact_small_integer_node(const detail::SymbolicNodePtr &node, int min_value, int max_value)
Result< Verified< EvaluatedTransform > > TransformEngineResult
const ExprPtr & rhs
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
受检变换成功时返回在 conditions 和收敛域 roc 条件下有效的已求值表达式。 支持性未决或收敛条件无法表示时,返回外层 Inconclusive 错误。