LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transform_z.cpp
浏览该文件的文档.
4#include <exception>
5
6namespace LMCAS {
7using namespace transform_detail;
8
9static bool zt_is_exp_seq(const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
10 std::shared_ptr<SymbolicExpr>& base_out) {
11 if (!f || !detail::node(f)) {
12 return false;
13 }
14 auto power = std::dynamic_pointer_cast<const PowerNode>(detail::node(f));
15 if (!power) {
16 return false;
17 }
18 auto exponent = std::dynamic_pointer_cast<const VariableNode>(power->exponent());
19 if (!exponent || exponent->is_constant() || exponent->name() != n) {
20 return false;
21 }
22 auto base = detail::make_expression_ptr(power->base());
23 if (te_depends_on(base, n)) {
24 return false;
25 }
26 base_out = base;
27 return true;
28}
29
30static bool zt_is_weighted_exp(const std::shared_ptr<SymbolicExpr>& f,
31 const std::string& n,
32 std::shared_ptr<SymbolicExpr>& base) {
33 auto product = std::dynamic_pointer_cast<const MultiplyNode>(detail::node(f));
34 if (!product || product->operands().size() != 2) {
35 return false;
36 }
37 for (std::size_t i = 0; i < 2; ++i) {
38 auto variable = std::dynamic_pointer_cast<const VariableNode>(product->operands()[i]);
39 auto other = detail::make_expression_ptr(product->operands()[1 - i]);
40 if (variable && !variable->is_constant() && variable->name() == n &&
41 zt_is_exp_seq(other, n, base)) {
42 return true;
43 }
44 }
45 return false;
46}
47
49
51 const std::shared_ptr<SymbolicExpr>& f, const std::string& n) {
52 auto variable = std::dynamic_pointer_cast<const VariableNode>(detail::node(f));
53 if (variable && !variable->is_constant() && variable->name() == n) {
55 }
56 auto power = std::dynamic_pointer_cast<const PowerNode>(detail::node(f));
57 if (!power) {
59 }
60 variable = std::dynamic_pointer_cast<const VariableNode>(power->base());
61 if (!variable || variable->is_constant() || variable->name() != n) {
63 }
64 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
65 BigInt integer;
68 }
69 if (integer == BigInt(2)) return ZPolynomialPattern::Quadratic;
70 if (integer == BigInt(3)) return ZPolynomialPattern::Cubic;
72}
73
74static std::shared_ptr<SymbolicExpr> zt_abs_expr(const std::shared_ptr<SymbolicExpr>& expr) {
75 if (!expr || !LMCAS::detail::node(expr)) return nullptr;
79 std::vector<std::shared_ptr<const SymbolicNode>>{LMCAS::detail::node(expr)}));
80}
81
82static std::vector<std::shared_ptr<SymbolicExpr>> zt_unit_roc(const std::string& z) {
83 auto condition = te_gt_condition(zt_abs_expr(SymbolicExpr::variable(z)),
84 SymbolicExpr::number(1));
85 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
86 : std::vector<std::shared_ptr<SymbolicExpr>>{};
87}
88
89static std::vector<std::shared_ptr<SymbolicExpr>> zt_base_roc(
90 const std::shared_ptr<SymbolicExpr>& base,
91 const std::string& z) {
92 auto condition = te_gt_condition(zt_abs_expr(SymbolicExpr::variable(z)),
93 zt_abs_expr(base));
94 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
95 : std::vector<std::shared_ptr<SymbolicExpr>>{};
96}
97
98static std::vector<std::shared_ptr<SymbolicExpr>> zt_lookup_roc(
99 const std::shared_ptr<SymbolicExpr>& f, const std::string& n, const std::string& z) {
101 std::shared_ptr<SymbolicExpr> base;
102 if (zt_is_exp_seq(f, n, base) || zt_is_weighted_exp(f, n, base)) return zt_base_roc(base, z);
103 bool is_sin = false;
104 std::shared_ptr<SymbolicExpr> frequency;
105 if (te_is_trig(f, n, is_sin, frequency)) return zt_unit_roc(z);
106 return {};
107}
108
109static std::vector<std::shared_ptr<SymbolicExpr>> zt_roc(
110 const std::shared_ptr<SymbolicExpr>& f, const std::string& n, const std::string& z) {
111 if (!f || !detail::node(f)) return {};
112 auto addition = std::dynamic_pointer_cast<const AddNode>(detail::node(f));
113 if (addition) {
114 std::vector<std::shared_ptr<SymbolicExpr>> combined;
115 for (const auto& operand : addition->operands()) {
116 auto conditions = zt_roc(detail::make_expression_ptr(operand), n, z);
117 combined.insert(combined.end(), conditions.begin(), conditions.end());
118 }
119 return combined;
120 }
121 if (!te_depends_on(f, n)) return zt_unit_roc(z);
122 auto [coefficient, body] = te_split_coeff(f, n);
123 if (!coefficient->is_one()) return zt_roc(body, n, z);
124 return zt_lookup_roc(f, n, z);
125}
126
127static std::shared_ptr<SymbolicExpr> zt_polynomial(
128 const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
129 const std::shared_ptr<SymbolicExpr>& z, const std::string& z_var, ComputationContext& context) {
130
131 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
132 (context).limits().max_ast_nodes, "transform");
133 auto pattern = zt_polynomial_pattern(f, n);
134 if (pattern == ZPolynomialPattern::None) return nullptr;
135 if (pattern == ZPolynomialPattern::Cubic) {
136 auto square = SymbolicExpr::power(SymbolicExpr::variable(n), SymbolicExpr::number(2));
137 auto quadratic = zt_polynomial(square, n, z, z_var, context);
139 SymbolicExpr::multiply(SymbolicExpr::number(-1), z),
140 detail::make_expression_ptr(detail::differentiate_node(detail::node(quadratic), z_var, transform_budget)))), transform_budget));
141 }
142 auto denominator = SymbolicExpr::power(SymbolicExpr::add(z, SymbolicExpr::number(-1)),
143 SymbolicExpr::number(pattern == ZPolynomialPattern::Linear ? 2 : 3));
144 auto numerator = pattern == ZPolynomialPattern::Linear ? z : SymbolicExpr::multiply(z,
145 SymbolicExpr::add(z, SymbolicExpr::number(1)));
146 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(numerator, denominator)), transform_budget));
147}
148
149static std::shared_ptr<SymbolicExpr> zt_exponential(
150 const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
151 const std::shared_ptr<SymbolicExpr>& z, ComputationContext& context) {
152
153 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
154 (context).limits().max_ast_nodes, "transform");
155 std::shared_ptr<SymbolicExpr> base;
156 const bool plain = zt_is_exp_seq(f, n, base);
157 if (!plain && !zt_is_weighted_exp(f, n, base)) return nullptr;
158 auto difference = SymbolicExpr::add(z, SymbolicExpr::multiply(SymbolicExpr::number(-1), base));
159 if (plain) return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(z, difference)), transform_budget));
160 auto denominator = SymbolicExpr::power(difference, SymbolicExpr::number(2));
161 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(SymbolicExpr::multiply(base, z), denominator)), transform_budget));
162}
163
164static std::shared_ptr<SymbolicExpr> zt_trigonometric(
165 const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
166 const std::shared_ptr<SymbolicExpr>& z, ComputationContext& context) {
167
168 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
169 (context).limits().max_ast_nodes, "transform");
170 bool is_sin = false;
171 std::shared_ptr<SymbolicExpr> frequency;
172 if (!te_is_trig(f, n, is_sin, frequency)) return nullptr;
173 auto cosine = SymbolicExpr::cos(frequency);
174 auto cross = SymbolicExpr::multiply(SymbolicExpr::multiply(SymbolicExpr::number(-2), z), cosine);
175 auto denominator = SymbolicExpr::add(SymbolicExpr::add(
176 SymbolicExpr::power(z, SymbolicExpr::number(2)), cross), SymbolicExpr::number(1));
177 auto factor = is_sin ? SymbolicExpr::sin(frequency) : SymbolicExpr::add(z,
178 SymbolicExpr::multiply(SymbolicExpr::number(-1), cosine));
179 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(SymbolicExpr::multiply(z, factor), denominator)), transform_budget));
180}
181
182static std::shared_ptr<SymbolicExpr> zt_unevaluated(
183 const std::shared_ptr<SymbolicExpr>& f, const std::string& n, const std::string& z) {
187}
188
189static std::shared_ptr<SymbolicExpr> z_transform_core(
190 const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
191 const std::string& z, ComputationContext& context);
192
193static std::shared_ptr<SymbolicExpr> zt_sum(
194 const std::shared_ptr<SymbolicExpr>& f, const AddNode& addition,
195 const std::string& n, const std::string& z, ComputationContext& context) {
196 std::shared_ptr<SymbolicExpr> result;
197 for (const auto& operand : addition.operands()) {
198 auto transformed = z_transform_core(detail::make_expression_ptr(operand), n, z, context);
199 if (!transformed) return zt_unevaluated(f, n, z);
200 result = result ? SymbolicExpr::add(result, transformed) : transformed;
201 }
202 return result;
203}
204
205static std::shared_ptr<SymbolicExpr> z_transform_core(
206 const std::shared_ptr<SymbolicExpr>& f, const std::string& n,
207 const std::string& z, ComputationContext& context) {
208 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
209 (context).limits().max_ast_nodes, "transform");
210 auto step = context.consume_steps(1, "z_transform.recursive");
211 if (!step) {
212 return nullptr;
213 }
214 if (!f || !detail::node(f)) {
215 return nullptr;
216 }
217 auto zv = SymbolicExpr::variable(z);
218 auto addition = std::dynamic_pointer_cast<const AddNode>(detail::node(f));
219 if (addition) {
220 return zt_sum(f, *addition, n, z, context);
221 }
222 auto [coefficient, body] = te_split_coeff(f, n);
223 if (!coefficient->is_one()) {
224 auto transformed = z_transform_core(body, n, z, context);
225 if (transformed) {
226 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(coefficient, transformed)), transform_budget));
227 }
228 }
229 if (!te_depends_on(f, n)) {
230 auto denominator = SymbolicExpr::add(zv, SymbolicExpr::number(-1));
231 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(f, SymbolicExpr::divide(zv, denominator))), transform_budget));
232 }
233 auto polynomial = zt_polynomial(f, n, zv, z, context);
234 if (polynomial) {
235 return polynomial;
236 }
237 auto exponential = zt_exponential(f, n, zv, context);
238 if (exponential) {
239 return exponential;
240 }
241 auto trig = zt_trigonometric(f, n, zv, context);
242 return trig ? trig : zt_unevaluated(f, n, z);
243}
244
246 const std::shared_ptr<SymbolicExpr>& f_n,
247 const std::string& n,
248 const std::string& z,
250 const std::string operation = "z_transform";
251 auto valid = te_validate_expr_vars(f_n, n, z, context, operation);
252 if (!valid) return TransformEngineResult::failure(valid.error());
253 auto step = context.consume_steps(8, operation);
254 if (!step) return TransformEngineResult::failure(step.error());
255 try {
256 auto expression = z_transform_core(f_n, n, z, context);
257 auto final_access = context.consume_steps(0, operation);
258 if (!final_access) {
259 return TransformEngineResult::failure(final_access.error());
260 }
261 auto result = te_wrap_transform_result(std::move(expression), operation);
262 if (result) {
263 result.value().value.roc = zt_roc(f_n, n, z);
264 }
265 return result;
266 } catch (const std::bad_alloc&) {
268 "transform allocation failed",
269 operation);
270 } catch (const std::exception& e) {
272 e.what(), operation);
273 }
274}
275
277 const std::shared_ptr<SymbolicExpr>& f_n,
278 const std::string& n,
279 const std::string& z) {
281 return z_transform_checked(f_n, n, z, context);
282}
283
284}
加法节点,表示多个操作数的求和。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static std::shared_ptr< const SymbolicNode > create_variable(const std::string &name)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, 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
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
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_gt_condition(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs)
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)
static bool zt_is_weighted_exp(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, std::shared_ptr< SymbolicExpr > &base)
const std::string & variable
static std::vector< std::shared_ptr< SymbolicExpr > > zt_lookup_roc(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::string &z)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
static std::shared_ptr< SymbolicExpr > zt_abs_expr(const std::shared_ptr< SymbolicExpr > &expr)
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
static std::shared_ptr< SymbolicExpr > z_transform_core(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::string &z, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > zt_polynomial(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::shared_ptr< SymbolicExpr > &z, const std::string &z_var, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > zt_unevaluated(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::string &z)
static std::shared_ptr< SymbolicExpr > zt_sum(const std::shared_ptr< SymbolicExpr > &f, const AddNode &addition, const std::string &n, const std::string &z, ComputationContext &context)
static std::vector< std::shared_ptr< SymbolicExpr > > zt_base_roc(const std::shared_ptr< SymbolicExpr > &base, const std::string &z)
static std::vector< std::shared_ptr< SymbolicExpr > > zt_unit_roc(const std::string &z)
const ExprPtr & exponent
static ZPolynomialPattern zt_polynomial_pattern(const std::shared_ptr< SymbolicExpr > &f, const std::string &n)
static bool zt_is_exp_seq(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, std::shared_ptr< SymbolicExpr > &base_out)
Result< Verified< EvaluatedTransform > > TransformEngineResult
static std::shared_ptr< SymbolicExpr > zt_exponential(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::shared_ptr< SymbolicExpr > &z, ComputationContext &context)
TransformEngineResult z_transform_checked(const std::shared_ptr< SymbolicExpr > &f_n, const std::string &n, const std::string &z, ComputationContext &context)
const ExprPtr & denominator
static std::vector< std::shared_ptr< SymbolicExpr > > zt_roc(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::string &z)
__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 > const std::string & z_var
static std::shared_ptr< SymbolicExpr > zt_trigonometric(const std::shared_ptr< SymbolicExpr > &f, const std::string &n, const std::shared_ptr< SymbolicExpr > &z, ComputationContext &context)