LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transform_fourier.cpp
浏览该文件的文档.
7#include <cmath>
8#include <exception>
9
10namespace LMCAS {
11using namespace transform_detail;
12
13
14static std::shared_ptr<SymbolicExpr> te_fourier_unevaluated(
15 const std::shared_ptr<SymbolicExpr>& f, const std::string& t,
16 const std::string& omega) {
20}
21
22static bool te_is_abs_variable(const std::shared_ptr<const SymbolicNode>& node,
23 const std::string& variable) {
24 auto function = std::dynamic_pointer_cast<const FunctionNode>(node);
26 function->arguments().size() != 1) return false;
27 auto argument = std::dynamic_pointer_cast<const VariableNode>(function->arguments()[0]);
28 return argument && !argument->is_constant() && argument->name() == variable;
29}
30static std::shared_ptr<SymbolicExpr> te_abs_decay(
31 const std::shared_ptr<SymbolicExpr>& f, const std::string& t, ComputationContext& context) {
32
33 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
34 (context).limits().max_ast_nodes, "transform");
35 auto function = std::dynamic_pointer_cast<const FunctionNode>(detail::node(f));
37 function->arguments().size() != 1) return nullptr;
38 auto argument = detail::make_expression_ptr(function->arguments()[0]);
39 auto parts = te_split_coeff(argument, t);
40 if (!te_is_abs_variable(detail::node(parts.second), t)) return nullptr;
42 SymbolicFactory::create_number(BigInt(-1)), detail::node(parts.first)}), transform_budget));
43}
44
45static std::shared_ptr<SymbolicExpr> te_decay_condition(
46 const std::shared_ptr<SymbolicExpr>& rate) {
47 auto product = std::dynamic_pointer_cast<const MultiplyNode>(detail::node(rate));
48 if (!product) return te_gt_condition(rate, SymbolicExpr::number(0));
49 std::vector<std::shared_ptr<const SymbolicNode>> factors;
50 for (const auto& factor : product->operands()) {
51 auto number = std::dynamic_pointer_cast<const NumberNode>(factor);
52 if (!number || !number->is_positive()) factors.push_back(factor);
53 }
55 return te_gt_condition(lhs, SymbolicExpr::number(0));
56}
57
58static bool te_accept_decay(const std::shared_ptr<SymbolicExpr>& rate,
59 const AssumptionContext& assumptions,
60 std::vector<std::shared_ptr<SymbolicExpr>>& conditions,
62 InferenceEngine inference(assumptions);
63 auto real = inference.query_real_checked(*rate, context);
64 if (!real) {
65 if (real.error().code == CasErrc::DomainError) return false;
66 throw real.error();
67 }
68 if (real.value() != Tribool::True) {
69 return false;
70 }
71 auto positive = inference.query_positive_checked(*rate, context);
72 if (!positive) {
73 throw positive.error();
74 }
75 if (positive.value() == Tribool::True) {
76 return true;
77 }
78 auto nonpositive = inference.query_nonpositive_checked(*rate, context);
79 if (!nonpositive) {
80 throw nonpositive.error();
81 }
82 if (positive.value() == Tribool::False || nonpositive.value() == Tribool::True) {
83 return false;
84 }
85 conditions.push_back(te_decay_condition(rate));
86 return true;
87}
88
89static std::shared_ptr<SymbolicExpr> te_abs_fourier(
90 const std::shared_ptr<SymbolicExpr>& rate, const std::string& omega, ComputationContext& context) {
91
92 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
93 (context).limits().max_ast_nodes, "transform");
94 auto two = SymbolicFactory::create_number(BigInt(2));
98 auto reciprocal = SymbolicFactory::create_power(
101 two, detail::node(rate), reciprocal}), transform_budget));
102}
103
104static std::shared_ptr<SymbolicExpr> te_gaussian_fourier(
105 const Rational& rate, const std::string& omega) {
107 auto coefficient = SymbolicExpr::sqrt(
108 SymbolicExpr::divide(pi, SymbolicExpr::number(rate)));
109 auto exponent = SymbolicExpr::multiply(SymbolicExpr::number(-Rational(1) / (Rational(4) * rate)),
110 SymbolicExpr::power(SymbolicExpr::variable(omega), SymbolicExpr::number(2)));
111 return SymbolicExpr::multiply(coefficient, SymbolicExpr::exp(exponent));
112}
113
114
115static std::shared_ptr<SymbolicExpr> fourier_transform_core(
116 const std::shared_ptr<SymbolicExpr>& f, const std::string& t,
117 const std::string& omega, ComputationContext& context,
118 const AssumptionContext& assumptions,
119 std::vector<std::shared_ptr<SymbolicExpr>>& conditions);
120
121static std::shared_ptr<SymbolicExpr> te_fourier_sum(
122 const AddNode& addition, const std::string& t, const std::string& omega,
123 ComputationContext& context, const AssumptionContext& assumptions,
124 std::vector<std::shared_ptr<SymbolicExpr>>& conditions) {
125 std::shared_ptr<SymbolicExpr> result;
126 for (const auto& operand : addition.operands()) {
127 auto transformed = fourier_transform_core(detail::make_expression_ptr(operand),
128 t, omega, context, assumptions, conditions);
129 if (!transformed) return nullptr;
130 result = result ? SymbolicExpr::add(result, transformed) : transformed;
131 }
132 return result;
133}
134
135static std::shared_ptr<SymbolicExpr> fourier_transform_core(
136 const std::shared_ptr<SymbolicExpr>& f, const std::string& t,
137 const std::string& omega, ComputationContext& context,
138 const AssumptionContext& assumptions,
139 std::vector<std::shared_ptr<SymbolicExpr>>& conditions) {
140 auto step = context.consume_steps(1, "fourier_transform.recursive");
141 if (!step) {
142 return nullptr;
143 }
144 if (!f || !detail::node(f)) {
145 return nullptr;
146 }
147 if (!te_depends_on(f, t)) {
148 return te_fourier_unevaluated(f, t, omega);
149 }
150 auto addition = std::dynamic_pointer_cast<const AddNode>(detail::node(f));
151 if (addition) {
152 return te_fourier_sum(*addition, t, omega, context, assumptions, conditions);
153 }
154 auto [coefficient, body] = te_split_coeff(f, t);
155 if (!coefficient->is_one()) {
156 auto transformed = fourier_transform_core(body, t, omega, context, assumptions, conditions);
157 if (transformed) {
158 return SymbolicExpr::multiply(coefficient, transformed);
159 }
160 }
161 if (const auto gaussian_rate = te_match_pure_gaussian(f, t)) {
162 return te_gaussian_fourier(*gaussian_rate, omega);
163 }
164 auto decay = te_abs_decay(f, t, context);
165 if (decay) {
166 if (te_accept_decay(decay, assumptions, conditions, context)) {
167 return te_abs_fourier(decay, omega, context);
168 }
169 return te_fourier_unevaluated(f, t, omega);
170 }
171 return te_fourier_unevaluated(f, t, omega);
172}
173
175 const std::shared_ptr<SymbolicExpr>& f,
176 const std::string& t,
177 const std::string& omega,
179 const std::string operation = "fourier_transform";
180 auto valid = te_validate_expr_vars(f, t, omega, 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 AssumptionContext empty_assumptions;
186 const auto& assumptions = context.assumptions() ? *context.assumptions() : empty_assumptions;
187 std::vector<std::shared_ptr<SymbolicExpr>> conditions;
188 auto expression = fourier_transform_core(f, t, omega, context, assumptions, conditions);
189 auto final_access = context.consume_steps(0, operation);
190 if (!final_access) {
191 return TransformEngineResult::failure(final_access.error());
192 }
193 auto result = te_wrap_transform_result(std::move(expression), operation);
194 if (result) result.value().value.conditions = std::move(conditions);
195 return result;
196 } catch (const CasError& error) {
197 return TransformEngineResult::failure(error);
198 } catch (const std::bad_alloc&) {
200 "transform allocation failed",
201 operation);
202 } catch (const std::exception& e) {
204 e.what(), operation);
205 }
206}
207
209 const std::shared_ptr<SymbolicExpr>& f,
210 const std::string& t,
211 const std::string& omega) {
213 return fourier_transform_checked(f, t, omega, context);
214}
215
216static std::shared_ptr<SymbolicExpr> inverse_fourier_transform_core(
217 const std::shared_ptr<SymbolicExpr>& F, const std::string& omega,
218 const std::string& t, ComputationContext& context) {
219 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
220 (context).limits().max_ast_nodes, "transform");
221 auto step = context.consume_steps(1, "inverse_fourier_transform.recursive");
222 if (!step) return nullptr;
223 if (!F || !LMCAS::detail::node(F)) return nullptr;
224 auto tv = SymbolicExpr::variable(t);
225 if (!te_depends_on(F, omega)) {
229 }
230 auto add_node = std::dynamic_pointer_cast<const AddNode>(LMCAS::detail::node(F));
231 if (add_node) {
232 std::shared_ptr<SymbolicExpr> result;
233 for (auto& op : add_node->operands()) {
236 if (!ift) {
240 }
241 result = result ? SymbolicExpr::add(result, ift) : ift;
242 }
243 return result;
244 }
245
246 auto canonical = te_abs_fourier(SymbolicExpr::number(1), omega, context);
247 if (detail::normalize_node(detail::node(F), transform_budget)->equals(*detail::node(canonical))) {
250 std::vector<std::shared_ptr<const SymbolicNode>>{detail::node(tv)}));
251 return SymbolicExpr::exp(SymbolicExpr::multiply(
252 SymbolicExpr::number(-1), abs_t));
253 }
254
255 if (const auto rate = te_match_pure_gaussian(F, omega)) {
257 auto coefficient = SymbolicExpr::divide(SymbolicExpr::number(1),
258 SymbolicExpr::sqrt(SymbolicExpr::multiply(
259 SymbolicExpr::number(Rational(4) * *rate), pi)));
260 auto exponent = SymbolicExpr::multiply(
261 SymbolicExpr::number(-Rational(1) / (Rational(4) * *rate)),
262 SymbolicExpr::power(tv, SymbolicExpr::number(2)));
263 return SymbolicExpr::multiply(
264 coefficient, SymbolicExpr::exp(exponent));
265 }
269}
270
272 const std::shared_ptr<SymbolicExpr>& F,
273 const std::string& omega,
274 const std::string& t,
276 const std::string operation = "inverse_fourier_transform";
277 auto valid = te_validate_expr_vars(F, omega, t, context, operation);
278 if (!valid) return TransformEngineResult::failure(valid.error());
279 auto step = context.consume_steps(8, operation);
280 if (!step) return TransformEngineResult::failure(step.error());
281 try {
282 auto expression = inverse_fourier_transform_core(
283 F, omega, t, context);
284 auto final_access = context.consume_steps(0, operation);
285 if (!final_access) {
286 return TransformEngineResult::failure(final_access.error());
287 }
288 auto result = te_wrap_transform_result(expression, operation);
289 if (!result) return result;
290 AssumptionContext empty_assumptions;
291 const auto& assumptions = context.assumptions() ? *context.assumptions() : empty_assumptions;
292 std::vector<std::shared_ptr<SymbolicExpr>> conditions;
293 auto round_trip = fourier_transform_core(
294 expression, t, omega, context, assumptions, conditions);
295 if (!round_trip || !conditions.empty() ||
299 "inverse Fourier round trip is not proved", operation);
300 }
301 auto verified = check_equivalent(round_trip, F, context);
302 if (!verified) return TransformEngineResult::failure(verified.error());
303 if (!std::holds_alternative<ProvedZeroResidual>(verified.value())) {
306 "inverse Fourier round trip is not proved", operation);
307 }
308 result.value().certificate =
309 ExactRoundTripProof{SymbolicExpr::number(0)};
310 return result;
311 } catch (const CasError& error) {
312 return TransformEngineResult::failure(error);
313 } catch (const std::bad_alloc&) {
315 "transform allocation failed",
316 operation);
317 } catch (const std::exception& e) {
319 e.what(), operation);
320 }
321}
322
324 const std::shared_ptr<SymbolicExpr>& F,
325 const std::string& omega,
326 const std::string& t) {
329}
330
331}
AssumptionContext class with scoped push/pop management.
加法节点,表示多个操作数的求和。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_variable(const std::string &name)
static std::shared_ptr< const SymbolicNode > create_power(std::shared_ptr< const SymbolicNode > base, std::shared_ptr< const SymbolicNode > exponent)
创建幂运算节点,自动处理指数为 0/1 及底数为 0/1 的情况.
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)
@ Fourier
Fourier 变换 F{f(t)}(omega)。
@ InverseFourier
逆 Fourier 变换 F-¹{F(omega)}(t)。
InferenceEngine class for deriving properties of composite expressions.
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)
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_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< Rational > te_match_pure_gaussian(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
const std::string & variable
ExprResult e()
static std::shared_ptr< SymbolicExpr > te_fourier_unevaluated(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &omega)
static std::shared_ptr< SymbolicExpr > te_gaussian_fourier(const Rational &rate, const std::string &omega)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ResidualCheckResult check_equivalent(const ExprPtr &left, const ExprPtr &right, ComputationContext &context, const LMCAS::EqvOptions &options)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > te_abs_fourier(const std::shared_ptr< SymbolicExpr > &rate, const std::string &omega, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > te_decay_condition(const std::shared_ptr< SymbolicExpr > &rate)
static std::shared_ptr< SymbolicExpr > inverse_fourier_transform_core(const std::shared_ptr< SymbolicExpr > &F, const std::string &omega, const std::string &t, ComputationContext &context)
@ True
Property definitely holds
@ False
Property definitely does not hold
TransformEngineResult inverse_fourier_transform_checked(const std::shared_ptr< SymbolicExpr > &F, const std::string &omega, const std::string &t, ComputationContext &context)
static bool te_accept_decay(const std::shared_ptr< SymbolicExpr > &rate, const AssumptionContext &assumptions, std::vector< std::shared_ptr< SymbolicExpr > > &conditions, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > fourier_transform_core(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &omega, ComputationContext &context, const AssumptionContext &assumptions, std::vector< std::shared_ptr< SymbolicExpr > > &conditions)
static bool te_is_abs_variable(const std::shared_ptr< const SymbolicNode > &node, const std::string &variable)
const ExprPtr RelationOp op
const ExprPtr & exponent
Result< Verified< EvaluatedTransform > > TransformEngineResult
static std::shared_ptr< SymbolicExpr > te_abs_decay(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, ComputationContext &context)
ExprResult pi()
static std::shared_ptr< SymbolicExpr > te_fourier_sum(const AddNode &addition, const std::string &t, const std::string &omega, ComputationContext &context, const AssumptionContext &assumptions, std::vector< std::shared_ptr< SymbolicExpr > > &conditions)
TransformEngineResult fourier_transform_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &t, const std::string &omega, ComputationContext &context)
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
__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