LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transform_inverse_laplace.cpp
浏览该文件的文档.
4#include <cmath>
5#include <exception>
6
7namespace LMCAS {
8using namespace transform_detail;
9
10static std::shared_ptr<SymbolicExpr> te_unevaluated_inv_laplace(
11 const std::shared_ptr<SymbolicExpr>& F, const std::string& s, const std::string& t) {
15}
16static std::shared_ptr<SymbolicExpr> te_inverse_pole_term(
17 const AddNode& addition, std::size_t i, const std::string& variable) {
18 auto symbol = std::dynamic_pointer_cast<const VariableNode>(addition.operands()[i]);
19 if (!symbol || symbol->is_constant() || symbol->name() != variable) return nullptr;
21 SymbolicFactory::create_number(BigInt(-1)), addition.operands()[1 - i]}));
22}
23
24static std::shared_ptr<SymbolicExpr> te_inverse_pole(
25 const std::shared_ptr<const SymbolicNode>& base, const std::string& variable) {
26 auto addition = std::dynamic_pointer_cast<const AddNode>(base);
27 if (!addition || addition->operands().size() != 2) return nullptr;
28 auto pole = te_inverse_pole_term(*addition, 0, variable);
29 if (pole) return pole;
30 return te_inverse_pole_term(*addition, 1, variable);
31}
32
33static std::shared_ptr<SymbolicExpr> te_inv_power(
34 const std::shared_ptr<SymbolicExpr>& F, const std::string& s,
35 const std::string& t, ComputationContext& context) {
36 if (!F || !LMCAS::detail::node(F)) {
37 return nullptr;
38 }
39 auto tv = SymbolicExpr::variable(t);
40 auto pw = std::dynamic_pointer_cast<const PowerNode>(LMCAS::detail::node(F));
41 if (!pw) {
42 return nullptr;
43 }
44 BigInt exponent;
45 if (!try_get_integer_value(std::dynamic_pointer_cast<const NumberNode>(pw->exponent()), exponent) ||
46 !exponent.is_negative()) {
47 return nullptr;
48 }
49 const BigInt n = -exponent;
50 auto make_exp = [&](const std::shared_ptr<SymbolicExpr>& a) {
51 auto arg = SymbolicExpr::multiply(a, tv);
54 std::vector<std::shared_ptr<const SymbolicNode>>{LMCAS::detail::node(arg)}));
55 };
56 auto bv = std::dynamic_pointer_cast<const VariableNode>(pw->base());
57 if (bv && !bv->is_constant() && bv->name() == s) {
58 if (n == BigInt(1)) {
59 return SymbolicExpr::number(1);
60 }
61 return SymbolicExpr::divide(SymbolicExpr::power(tv, SymbolicExpr::number(n - BigInt(1))),
62 SymbolicExpr::number(te_factorial(n - BigInt(1), context)));
63 }
64 auto pole = te_inverse_pole(pw->base(), s);
65 if (pole) {
66 if (n == BigInt(1)) {
67 if (te_is_zero(pole)) {
68 return SymbolicExpr::number(1);
69 }
70 return make_exp(pole);
71 }
72 auto tp = SymbolicExpr::power(tv, SymbolicExpr::number(n - BigInt(1)));
73 auto fv = SymbolicExpr::number(te_factorial(n - BigInt(1), context));
74 if (te_is_zero(pole)) {
75 return SymbolicExpr::divide(tp, fv);
76 }
77 return SymbolicExpr::divide(SymbolicExpr::multiply(tp, make_exp(pole)), fv);
78 }
79 return nullptr;
80}
82 const std::shared_ptr<const SymbolicNode>& expression,
83 const std::string& variable) {
84 const auto power = std::dynamic_pointer_cast<const PowerNode>(expression);
85 if (!power) return false;
86 const auto exponent = te_number_value(power->exponent());
87 return exponent && *exponent < Rational(0) &&
89}
90
91static std::shared_ptr<SymbolicExpr> te_inv_product(
92 const std::shared_ptr<SymbolicExpr>& F, const std::string& s,
93 const std::string& t, ComputationContext& context) {
94 if (!F || !LMCAS::detail::node(F)) {
95 return nullptr;
96 }
97 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(F));
98 if (!mul || mul->operands().size() < 2) {
99 return nullptr;
100 }
101 std::vector<std::shared_ptr<const SymbolicNode>> num_parts;
102 std::shared_ptr<const SymbolicNode> den_part = nullptr;
103 for (const auto& op : mul->operands()) {
104 if (!den_part && te_is_denominator_factor(op, s)) {
105 den_part = op;
106 continue;
107 }
108 num_parts.push_back(op);
109 }
110 if (!den_part) {
111 return nullptr;
112 }
113 std::shared_ptr<SymbolicExpr> num_expr;
114 if (num_parts.empty()) {
115 num_expr = SymbolicExpr::number(1);
116 } else if (num_parts.size() == 1) {
117 num_expr = LMCAS::detail::make_expression_ptr(num_parts[0]);
118 } else {
120 }
121 if (!te_depends_on(num_expr, s)) {
122 auto inv = te_inv_power(LMCAS::detail::make_expression_ptr(den_part), s, t, context);
123 if (inv) {
124 return SymbolicExpr::multiply(num_expr, inv);
125 }
126 }
127 return nullptr;
128}
129
130static std::shared_ptr<SymbolicExpr> inverse_laplace_core(
131 const std::shared_ptr<SymbolicExpr>& F, const std::string& s,
132 const std::string& t, ComputationContext& context) {
133 auto step = context.consume_steps(1, "inverse_laplace.recursive");
134 if (!step) {
135 return nullptr;
136 }
137 if (!F || !LMCAS::detail::node(F)) {
138 return nullptr;
139 }
140 if (te_is_zero(F)) {
141 return SymbolicExpr::number(0);
142 }
143 auto add = std::dynamic_pointer_cast<const AddNode>(LMCAS::detail::node(F));
144 if (add) {
145 std::shared_ptr<SymbolicExpr> result;
146 for (auto& op : add->operands()) {
147 auto ilt = inverse_laplace_core(
149 if (!ilt) {
150 return te_unevaluated_inv_laplace(F, s, t);
151 }
152 result = result ? SymbolicExpr::add(result, ilt) : ilt;
153 }
154 return result;
155 }
156 auto [coeff, body] = te_split_coeff(F, s);
157 if (!coeff->is_one()) {
158 auto ilt_body = inverse_laplace_core(body, s, t, context);
159 if (ilt_body) {
160 return SymbolicExpr::multiply(coeff, ilt_body);
161 }
162 }
163 auto pw_res = te_inv_power(F, s, t, context);
164 if (pw_res) {
165 return pw_res;
166 }
167 auto prod_res = te_inv_product(F, s, t, context);
168 if (prod_res) {
169 return prod_res;
170 }
171 return te_unevaluated_inv_laplace(F, s, t);
172}
173
175 const std::shared_ptr<SymbolicExpr>& F,
176 const std::string& s,
177 const std::string& t,
179 const std::string operation = "inverse_laplace";
180 auto valid = te_validate_expr_vars(F, s, t, context, operation);
181 if (!valid) return TransformEngineResult::failure(valid.error());
182 auto step = context.consume_steps(8, operation);
183 if (!step) return TransformEngineResult::failure(step.error());
184 try {
185 auto expression = inverse_laplace_core(F, s, t, context);
186 auto final_access = context.consume_steps(0, operation);
187 if (!final_access) {
188 return TransformEngineResult::failure(final_access.error());
189 }
190 auto result = te_wrap_transform_result(expression, operation);
191 if (!result) return result;
192 auto round_trip = laplace_transform_core(
193 expression, t, s, context);
194 if (!round_trip ||
198 "inverse Laplace round trip is not proved", operation);
199 }
200 auto verified = check_equivalent(round_trip, F, context);
201 if (!verified) return TransformEngineResult::failure(verified.error());
202 if (!std::holds_alternative<ProvedZeroResidual>(verified.value())) {
205 "inverse Laplace round trip is not proved", operation);
206 }
207 result.value().certificate =
208 ExactRoundTripProof{SymbolicExpr::number(0)};
209 return result;
210 } catch (const CasError& error) {
211 return TransformEngineResult::failure(error);
212 } catch (const std::bad_alloc&) {
214 "transform allocation failed",
215 operation);
216 } catch (const std::exception& e) {
218 e.what(), operation);
219 }
220}
221
223 const std::shared_ptr<SymbolicExpr>& F,
224 const std::string& s,
225 const std::string& t) {
227 return inverse_laplace_checked(F, s, t, context);
228}
229
230}
加法节点,表示多个操作数的求和。
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)
@ InverseLaplace
逆 Laplace 变换 L-¹{F(s)}(t)。
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)
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)
std::pair< std::shared_ptr< SymbolicExpr >, std::shared_ptr< SymbolicExpr > > te_split_coeff(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
bool te_is_zero(const std::shared_ptr< SymbolicExpr > &expression)
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)
BigInt te_factorial(const BigInt &n, ComputationContext &context)
std::optional< Rational > te_number_value(const std::shared_ptr< const SymbolicNode > &node)
const std::string & variable
ExprResult e()
static std::shared_ptr< SymbolicExpr > te_unevaluated_inv_laplace(const std::shared_ptr< SymbolicExpr > &F, const std::string &s, const std::string &t)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ResidualCheckResult check_equivalent(const ExprPtr &left, const ExprPtr &right, ComputationContext &context, const LMCAS::EqvOptions &options)
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
static std::shared_ptr< SymbolicExpr > inverse_laplace_core(const std::shared_ptr< SymbolicExpr > &F, const std::string &s, const std::string &t, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > te_inverse_pole_term(const AddNode &addition, std::size_t i, const std::string &variable)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
static bool te_is_denominator_factor(const std::shared_ptr< const SymbolicNode > &expression, const std::string &variable)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const ExprPtr RelationOp op
const ExprPtr & exponent
__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
Result< Verified< EvaluatedTransform > > TransformEngineResult
static std::shared_ptr< SymbolicExpr > te_inverse_pole(const std::shared_ptr< const SymbolicNode > &base, const std::string &variable)
TransformEngineResult inverse_laplace_checked(const std::shared_ptr< SymbolicExpr > &F, const std::string &s, const std::string &t, 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
static std::shared_ptr< SymbolicExpr > te_inv_product(const std::shared_ptr< SymbolicExpr > &F, const std::string &s, const std::string &t, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > te_inv_power(const std::shared_ptr< SymbolicExpr > &F, const std::string &s, const std::string &t, ComputationContext &context)