LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transform_laplace.cpp
浏览该文件的文档.
4#include <exception>
5
6namespace LMCAS {
7using namespace transform_detail;
8
9static std::shared_ptr<SymbolicExpr> te_unevaluated_laplace(
10 const std::shared_ptr<SymbolicExpr>& f, const std::string& t, const std::string& s) {
14}
15static bool te_is_power_of_var(const std::shared_ptr<SymbolicExpr>& e, const std::string& v, BigInt& n) {
16 if (!e || !LMCAS::detail::node(e)) {
17 return false;
18 }
19 auto vn = std::dynamic_pointer_cast<const VariableNode>(LMCAS::detail::node(e));
20 if (vn && !vn->is_constant() && vn->name() == v) { n = BigInt(1); return true; }
21 auto pw = std::dynamic_pointer_cast<const PowerNode>(LMCAS::detail::node(e));
22 if (!pw) {
23 return false;
24 }
25 auto bv = std::dynamic_pointer_cast<const VariableNode>(pw->base());
26 if (!bv || bv->is_constant() || bv->name() != v) {
27 return false;
28 }
29 return try_get_integer_value(std::dynamic_pointer_cast<const NumberNode>(pw->exponent()), n) &&
30 !n.is_negative();
31}
32static bool te_is_hyp(const std::shared_ptr<SymbolicExpr>& e, const std::string& v,
33 bool& is_sinh, std::shared_ptr<SymbolicExpr>& freq) {
34 if (!e || !LMCAS::detail::node(e)) {
35 return false;
36 }
37 auto fn = std::dynamic_pointer_cast<const FunctionNode>(LMCAS::detail::node(e));
38 if (!fn || fn->arguments().empty()) {
39 return false;
40 }
41 if (fn->type() != FunctionNode::FuncType::Sinh && fn->type() != FunctionNode::FuncType::Cosh) {
42 return false;
43 }
44 is_sinh = (fn->type() == FunctionNode::FuncType::Sinh);
45 freq = te_linear_coefficient(fn->arguments()[0], v);
46 return freq != nullptr;
47}
48
49static bool te_extract_exp(const std::shared_ptr<SymbolicExpr>& e, const std::string& t,
50 std::shared_ptr<SymbolicExpr>& a_out, std::shared_ptr<SymbolicExpr>& rem_out) {
51 if (!e || !LMCAS::detail::node(e)) {
52 return false;
53 }
54 auto fn = std::dynamic_pointer_cast<const FunctionNode>(LMCAS::detail::node(e));
55 if (fn && fn->type() == FunctionNode::FuncType::Exp && !fn->arguments().empty()) {
56 a_out = te_linear_coefficient(fn->arguments()[0], t);
57 if (a_out) {
59 return true;
60 }
61 }
62 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(e));
63 if (mul) {
64 for (size_t i = 0; i < mul->operands().size(); ++i) {
65 auto fac = LMCAS::detail::make_expression_ptr(mul->operands()[i]);
66 std::shared_ptr<SymbolicExpr> at, rt;
67 if (te_extract_exp(fac, t, at, rt)) {
68 std::vector<std::shared_ptr<const SymbolicNode>> rest = mul->operands();
69 rest.erase(rest.begin() + static_cast<std::ptrdiff_t>(i));
71 SymbolicFactory::create_multiply(std::move(rest)));
72 a_out = at; return true;
73 }
74 }
75 }
76 return false;
77}
78
79static std::shared_ptr<SymbolicExpr> te_laplace_lookup(
80 const std::shared_ptr<SymbolicExpr>& f, const std::string& t,
81 const std::string& s, ComputationContext& context) {
82 if (!f || !LMCAS::detail::node(f)) return nullptr;
83 auto sv = SymbolicExpr::variable(s);
84 if (!te_depends_on(f, t)) return SymbolicExpr::divide(f, sv);
85 BigInt n;
86 if (te_is_power_of_var(f, t, n)) {
87 return SymbolicExpr::divide(SymbolicExpr::number(te_factorial(n, context)),
88 SymbolicExpr::power(sv, SymbolicExpr::number(n + BigInt(1))));
89 }
90 bool is_sin = false; std::shared_ptr<SymbolicExpr> freq;
91 if (te_is_trig(f, t, is_sin, freq)) {
92 auto den = SymbolicExpr::add(SymbolicExpr::power(sv, SymbolicExpr::number(2)), SymbolicExpr::power(freq, SymbolicExpr::number(2)));
93 return is_sin ? SymbolicExpr::divide(freq, den) : SymbolicExpr::divide(sv, den);
94 }
95 bool is_sinh = false; std::shared_ptr<SymbolicExpr> hf;
96 if (te_is_hyp(f, t, is_sinh, hf)) {
97 auto den = SymbolicExpr::add(SymbolicExpr::power(sv, SymbolicExpr::number(2)), SymbolicExpr::multiply(SymbolicExpr::number(-1), SymbolicExpr::power(hf, SymbolicExpr::number(2))));
98 return is_sinh ? SymbolicExpr::divide(hf, den) : SymbolicExpr::divide(sv, den);
99 }
100 std::shared_ptr<SymbolicExpr> a, rem;
101 if (te_extract_exp(f, t, a, rem) && !te_depends_on(rem, t))
102 return SymbolicExpr::divide(rem, SymbolicExpr::add(sv, SymbolicExpr::multiply(SymbolicExpr::number(-1), a)));
103 return nullptr;
104}
105
106static std::vector<std::shared_ptr<SymbolicExpr>> te_laplace_roc(
107 const std::shared_ptr<SymbolicExpr>& f,
108 const std::string& t,
109 const std::string& s) {
110 if (!f || !LMCAS::detail::node(f)) return {};
111 auto sv = SymbolicExpr::variable(s);
112 if (!te_depends_on(f, t)) {
113 auto condition = te_gt_condition(sv, SymbolicExpr::number(0));
114 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
115 : std::vector<std::shared_ptr<SymbolicExpr>>{};
116 }
117 BigInt n;
118 if (te_is_power_of_var(f, t, n)) {
119 auto condition = te_gt_condition(sv, SymbolicExpr::number(0));
120 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
121 : std::vector<std::shared_ptr<SymbolicExpr>>{};
122 }
123 bool is_sin = false;
124 std::shared_ptr<SymbolicExpr> freq;
125 if (te_is_trig(f, t, is_sin, freq)) {
126 auto condition = te_gt_condition(sv, SymbolicExpr::number(0));
127 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
128 : std::vector<std::shared_ptr<SymbolicExpr>>{};
129 }
130 std::shared_ptr<SymbolicExpr> a;
131 std::shared_ptr<SymbolicExpr> rem;
132 if (te_extract_exp(f, t, a, rem) && !te_depends_on(rem, t)) {
133 auto condition = te_gt_condition(sv, a);
134 return condition ? std::vector<std::shared_ptr<SymbolicExpr>>{condition}
135 : std::vector<std::shared_ptr<SymbolicExpr>>{};
136 }
137 return {};
138}
139
140static std::shared_ptr<SymbolicExpr> te_laplace_sum(
141 const std::shared_ptr<SymbolicExpr>& f, const AddNode& addition,
142 const std::string& t, const std::string& s, ComputationContext& context) {
143 std::shared_ptr<SymbolicExpr> result;
144 for (const auto& operand : addition.operands()) {
145 auto transformed = laplace_transform_core(
147 if (!transformed) return te_unevaluated_laplace(f, t, s);
148 result = result ? SymbolicExpr::add(result, transformed) : transformed;
149 }
150 return result;
151}
152
153std::shared_ptr<SymbolicExpr> transform_detail::laplace_transform_core(
154 const std::shared_ptr<SymbolicExpr>& f, const std::string& t,
155 const std::string& s, ComputationContext& context) {
156 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
157 (context).limits().max_ast_nodes, "transform");
158 auto step = context.consume_steps(1, "laplace_transform.recursive");
159 if (!step) {
160 return nullptr;
161 }
162 if (!f || !LMCAS::detail::node(f)) {
163 return nullptr;
164 }
165 if (te_is_zero(f)) {
166 return SymbolicExpr::number(0);
167 }
168 if (!te_depends_on(f, t)) {
169 return SymbolicExpr::divide(f, SymbolicExpr::variable(s));
170 }
171 auto add = std::dynamic_pointer_cast<const AddNode>(LMCAS::detail::node(f));
172 if (add) {
173 return te_laplace_sum(f, *add, t, s, context);
174 }
175 auto [coeff, body] = te_split_coeff(f, t);
176 if (!coeff->is_one()) {
177 auto lt_body = laplace_transform_core(body, t, s, context);
178 if (lt_body) {
179 return SymbolicExpr::multiply(coeff, lt_body);
180 }
181 }
182 std::shared_ptr<SymbolicExpr> a_shift, remainder;
183 if (te_extract_exp(f, t, a_shift, remainder)) {
184 if (te_depends_on(remainder, t)) {
185 auto lt_rem = laplace_transform_core(remainder, t, s, context);
186 if (lt_rem) {
187 return detail::make_expression_ptr(detail::substitute_node(detail::node(lt_rem), s, detail::node(SymbolicExpr::add(SymbolicExpr::variable(s), SymbolicExpr::multiply(SymbolicExpr::number(-1), a_shift))), transform_budget));
188 }
189 } else {
190 return SymbolicExpr::divide(remainder, SymbolicExpr::add(SymbolicExpr::variable(s), SymbolicExpr::multiply(SymbolicExpr::number(-1), a_shift)));
191 }
192 }
193 auto lookup = te_laplace_lookup(f, t, s, context);
194 if (lookup) {
195 return lookup;
196 }
197 return te_unevaluated_laplace(f, t, s);
198}
199
201 const std::shared_ptr<SymbolicExpr>& f,
202 const std::string& t,
203 const std::string& s,
205 const std::string operation = "laplace_transform";
206 auto valid = te_validate_expr_vars(f, t, s, context, operation);
207 if (!valid) return TransformEngineResult::failure(valid.error());
208 auto step = context.consume_steps(8, operation);
209 if (!step) return TransformEngineResult::failure(step.error());
210 try {
211 auto expression = laplace_transform_core(f, t, s, context);
212 auto final_access = context.consume_steps(0, operation);
213 if (!final_access) {
214 return TransformEngineResult::failure(final_access.error());
215 }
216 auto result = te_wrap_transform_result(std::move(expression), operation);
217 if (result) {
218 result.value().value.roc = te_laplace_roc(f, t, s);
219 }
220 return result;
221 } catch (const CasError& error) {
222 return TransformEngineResult::failure(error);
223 } catch (const std::bad_alloc&) {
225 "transform allocation failed",
226 operation);
227 } catch (const std::exception& e) {
229 e.what(), operation);
230 }
231}
232
234 const std::shared_ptr<SymbolicExpr>& f,
235 const std::string& t,
236 const std::string& s) {
238 return laplace_transform_checked(f, t, s, context);
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 std::shared_ptr< const SymbolicNode > create_variable(const std::string &name)
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
Laplace 变换 L{f(t)}(s)。
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 substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, 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)
std::shared_ptr< SymbolicExpr > laplace_transform_core(const std::shared_ptr< SymbolicExpr > &expression, const std::string &input_var, const std::string &output_var, ComputationContext &context)
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_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)
BigInt te_factorial(const BigInt &n, ComputationContext &context)
TransformEngineResult laplace_transform_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &s, ComputationContext &context)
ExprResult e()
static std::shared_ptr< SymbolicExpr > te_unevaluated_laplace(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &s)
__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
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
static bool te_is_hyp(const std::shared_ptr< SymbolicExpr > &e, const std::string &v, bool &is_sinh, std::shared_ptr< SymbolicExpr > &freq)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static bool te_extract_exp(const std::shared_ptr< SymbolicExpr > &e, const std::string &t, std::shared_ptr< SymbolicExpr > &a_out, std::shared_ptr< SymbolicExpr > &rem_out)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
static std::vector< std::shared_ptr< SymbolicExpr > > te_laplace_roc(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &s)
Result< Verified< EvaluatedTransform > > TransformEngineResult
static bool te_is_power_of_var(const std::shared_ptr< SymbolicExpr > &e, const std::string &v, BigInt &n)
static std::shared_ptr< SymbolicExpr > te_laplace_sum(const std::shared_ptr< SymbolicExpr > &f, const AddNode &addition, const std::string &t, const std::string &s, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > te_laplace_lookup(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &s, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t