LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
calculus_inverse.cpp
浏览该文件的文档.
1#include <stdexcept>
3#include "root_of_utils.hpp"
7
8namespace LMCAS {
9
10using namespace calculus_utils_detail;
11
12
13static bool calculus_utils_contains_complex(const std::shared_ptr<const SymbolicNode>& node)
14{
15 if (!node) {
16 return false;
17 }
18
19 if (std::dynamic_pointer_cast<const ComplexNode>(node)) {
20 return true;
21 }
22 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
23 for (const auto& argument : function->arguments()) {
24 if (calculus_utils_contains_complex(argument)) {
25 return true;
26 }
27 }
28 return false;
29 }
30 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
31 for (const auto& operand : add->operands()) {
33 return true;
34 }
35 }
36 return false;
37 }
38 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
39 for (const auto& operand : multiply->operands()) {
41 return true;
42 }
43 }
44 return false;
45 }
46 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
47 return calculus_utils_contains_complex(power->base()) ||
48 calculus_utils_contains_complex(power->exponent());
49 }
50 return false;
51}
52
53static bool calculus_utils_is_negative_number(const std::shared_ptr<const NumberNode>& number)
54{
55 if (!number) {
56 return false;
57 }
58 if (std::holds_alternative<BigInt>(number->value())) {
59 return std::get<BigInt>(number->value()) < BigInt(0);
60 }
61 return std::get<Rational>(number->value()) < Rational(0);
62}
63
65{
66
67 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
68 (context).limits().max_ast_nodes, "transform");
70 function.arguments().size() != 1) {
71 return false;
72 }
73 auto argument = detail::make_expression_ptr(detail::normalize_node(function.arguments()[0], transform_budget));
74 auto number = argument
75 ? std::dynamic_pointer_cast<const NumberNode>(LMCAS::detail::node(argument))
76 : nullptr;
78}
79
81 const std::shared_ptr<const SymbolicNode>& node, ComputationContext& context);
82
83static bool any_nonreal_sqrt(
84 const std::vector<std::shared_ptr<const SymbolicNode>>& children, ComputationContext& context)
85{
86 for (const auto& child : children) {
88 return true;
89 }
90 }
91 return false;
92}
93
94static bool calculus_utils_contains_nonreal_sqrt(const std::shared_ptr<const SymbolicNode>& node, ComputationContext& context)
95{
96 if (!node) {
97 return false;
98 }
99
100 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
102 return true;
103 }
104 return any_nonreal_sqrt(function->arguments(), context);
105 }
106 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
107 return any_nonreal_sqrt(add->operands(), context);
108 }
109 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
110 return any_nonreal_sqrt(multiply->operands(), context);
111 }
112 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
113 return calculus_utils_contains_nonreal_sqrt(power->base(), context) ||
115 }
116 if (auto complex = std::dynamic_pointer_cast<const ComplexNode>(node)) {
119 }
120 return false;
121}
122
128
130 const std::shared_ptr<SymbolicExpr>& candidate,
131 std::shared_ptr<SymbolicExpr>& real_candidate, ComputationContext& context)
132{
133
134 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
135 (context).limits().max_ast_nodes, "transform");
136 real_candidate.reset();
137 auto simplified_candidate = rootof_simplify(candidate);
138 if (!simplified_candidate || !LMCAS::detail::node(simplified_candidate)) {
140 }
143 }
146 }
147
148 if (auto complex = std::dynamic_pointer_cast<const ComplexNode>(
149 LMCAS::detail::node(simplified_candidate))) {
150 auto imag = detail::make_expression_ptr(detail::normalize_node(complex->imag(), transform_budget));
151 if (!imag || !LMCAS::detail::node(imag)) {
153 }
154 if (imag->is_zero()) {
155 auto real = detail::make_expression_ptr(detail::normalize_node(complex->real(), transform_budget));
156 if (!real || !LMCAS::detail::node(real)) {
158 }
159 real_candidate = real;
161 }
163 }
164
165 if (calculus_utils_contains_complex(LMCAS::detail::node(simplified_candidate))) {
167 }
168
169 real_candidate = simplified_candidate;
171}
173 const std::vector<std::shared_ptr<SymbolicExpr>>& candidates,
174 const std::shared_ptr<SymbolicExpr>& candidate)
175{
176 for (const auto& existing : candidates) {
177 if (existing && LMCAS::detail::node(existing) &&
178 LMCAS::detail::node(existing)->equals(*LMCAS::detail::node(candidate))) {
179 return true;
180 }
181 }
182 return false;
183}
184
186 const std::vector<std::shared_ptr<SymbolicExpr>>& candidates,
187 const std::shared_ptr<SymbolicExpr>& equation, const std::string& var,
188 const std::string& operation, ComputationContext& context)
189try {
190
191 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
192 (context).limits().max_ast_nodes, "transform");
193 std::vector<std::shared_ptr<SymbolicExpr>> real_candidates;
194 real_candidates.reserve(candidates.size());
195 for (const auto& candidate : candidates) {
196 std::shared_ptr<SymbolicExpr> real_candidate;
197 auto status = calculus_utils_extract_real_candidate(candidate, real_candidate, context);
201 "inverse derivative candidate reality could not be proven", operation);
202 }
204 continue;
205 }
206 auto residual = detail::make_expression_ptr(detail::substitute_node(detail::node(equation), var, detail::node(real_candidate), transform_budget));
207 auto simplified = residual ? detail::make_expression_ptr(detail::normalize_node(detail::node(residual), transform_budget)) : nullptr;
208 if (!simplified || !LMCAS::detail::node(simplified)) {
211 "inverse derivative candidate verification produced a null residual", operation);
212 }
213 if (!simplified->is_zero()) {
214 continue;
215 }
216 if (!contains_inverse_candidate(real_candidates, real_candidate)) {
217 real_candidates.push_back(real_candidate);
218 }
219 }
220 return SymbolicExprVectorResult::success(std::move(real_candidates));
221} catch (const CasError& error) {
223} catch (const std::bad_alloc&) {
224 return SymbolicExprVectorResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
225} catch (const std::length_error& error) {
226 return SymbolicExprVectorResult::failure(CasErrc::ResourceLimit, error.what(), operation);
227} catch (const std::exception& error) {
228 return SymbolicExprVectorResult::failure(CasErrc::InternalInvariant, error.what(), operation);
229}
230
232 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
233 const std::vector<std::shared_ptr<SymbolicExpr>>& candidates,
234 const std::string& operation, ComputationContext& context)
235try {
236
237 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
238 (context).limits().max_ast_nodes, "transform");
239 if (candidates.empty()) {
242 "inverse point is outside the proven range",
243 operation);
244 }
245 if (candidates.size() != 1) {
248 "inverse derivative requires a unique inverse branch",
249 operation);
250 }
251
252 auto f_prime = detail::make_expression_ptr(detail::differentiate_node(detail::node(f), var, transform_budget));
253 if (!f_prime || !LMCAS::detail::node(f_prime)) {
256 "inverse derivative could not construct the derivative",
257 operation);
258 }
259
260 auto f_prime_at_x0 = detail::make_expression_ptr(detail::substitute_node(detail::node(f_prime), var, detail::node(candidates[0]), transform_budget));
261 auto simplified_derivative = f_prime_at_x0 ? detail::make_expression_ptr(detail::normalize_node(detail::node(f_prime_at_x0), transform_budget)) : nullptr;
262 if (!simplified_derivative || !LMCAS::detail::node(simplified_derivative)) {
265 "inverse derivative substitution produced a null expression",
266 operation);
267 }
268
269 if (simplified_derivative->is_zero()) {
272 "inverse derivative is undefined where f' is zero",
273 operation);
274 }
275
276 auto result = SymbolicExpr::divide(SymbolicExpr::number(1), simplified_derivative);
277 auto simplified = result ? detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget)) : nullptr;
278 if (!simplified || !LMCAS::detail::node(simplified)) {
281 "inverse derivative result construction failed",
282 operation);
283 }
284 return ExpressionResult::success(simplified);
285} catch (const CasError& error) {
286 return ExpressionResult::failure(error);
287} catch (const std::bad_alloc&) {
288 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
289} catch (const std::length_error& error) {
290 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
291} catch (const std::exception& error) {
292 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), operation);
293}
294
296 const FiniteSolutions& finite, const std::string& operation)
297{
298 std::vector<std::shared_ptr<SymbolicExpr>> values;
299 values.reserve(finite.values.size());
300 for (const auto& solution : finite.values) {
301 if (!solution.value || !LMCAS::detail::node(solution.value)) {
304 "checked solver returned a null inverse candidate",
305 operation);
306 }
307 auto candidate = rootof_simplify(solution.value);
308 if (!candidate || !LMCAS::detail::node(candidate)) {
311 "checked solver returned a malformed inverse candidate",
312 operation);
313 }
314 values.push_back(candidate);
315 }
316 return SymbolicExprVectorResult::success(std::move(values));
317}
318
320 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
321 const std::shared_ptr<SymbolicExpr>& point,
323{
324 const std::string operation = "inverse_derivative";
325 auto input = calculus_utils_validate_expr_target(f, var, point, context, operation);
326 if (!input) {
327 return ExpressionResult::failure(input.error());
328 }
329 auto step = context.consume_steps(4, operation);
330 if (!step) {
331 return ExpressionResult::failure(step.error());
332 }
333
334 try {
335 auto eq = SymbolicExpr::add(
336 f, SymbolicExpr::multiply(SymbolicExpr::number(-1), point));
337
338 std::vector<std::shared_ptr<SymbolicExpr>> candidates;
339 auto inverse = inverse_function_checked(f, var, point, context);
340 if (inverse) {
341 candidates = inverse.value();
342 } else {
343 return ExpressionResult::failure(inverse.error());
344 }
345 auto verified = verified_real_inverse_candidates(candidates, eq, var, operation, context);
346 if (!verified) {
347 return ExpressionResult::failure(verified.error());
348 }
349 return inverse_branch_derivative(f, var, verified.value(), operation, context);
350 } catch (const std::bad_alloc&) {
352 "inverse derivative allocation failed",
353 operation);
354 } catch (const std::exception& e) {
356 e.what(), operation);
357 }
358}
359
361 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
362 const std::shared_ptr<SymbolicExpr>& point)
363{
366}
367
369 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
370 const std::shared_ptr<SymbolicExpr>& y, ComputationContext& context)
371{
372 const std::string operation = "inverse_function";
373 auto input = calculus_utils_validate_expr_target(f, var, y, context, operation);
374 if (!input) {
375 return SymbolicExprVectorResult::failure(input.error());
376 }
377 auto step = context.consume_steps(4, operation);
378 if (!step) {
379 return SymbolicExprVectorResult::failure(step.error());
380 }
381
382 try {
383 auto eq = SymbolicExpr::eq(f, y);
384
385 auto solved = solve_equation(eq, var, context, SolveOptions{});
386 if (!solved) {
387 return SymbolicExprVectorResult::failure(solved.error());
388 }
389
390 const auto& solutions = solved.value();
391 if (std::holds_alternative<EmptySolutions>(solutions)) {
393 }
394 if (const auto* finite = std::get_if<FiniteSolutions>(&solutions)) {
395 return explicit_inverse_candidates(*finite, operation);
396 }
397
400 "inverse equation is outside the finite exact support domain",
401 operation);
402 } catch (const std::bad_alloc&) {
404 "inverse function allocation failed",
405 operation);
406 } catch (const std::exception& e) {
408 e.what(), operation);
409 }
410}
411
413 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
414 const std::shared_ptr<SymbolicExpr>& y)
415{
417 return inverse_function_checked(f, var, y, context);
418}
419
420}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sqrt
对数、绝对值、平方根。
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::vector< std::shared_ptr< SymbolicExpr > > value)
Result< void > calculus_utils_validate_expr_target(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const std::shared_ptr< SymbolicExpr > &target, ComputationContext &context, const std::string &operation)
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
bool contains_node_type(const SymbolicNodePtr &root)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::string const LimitExprPtr & point
ExprResult eq(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::shared_ptr< SymbolicExpr > rootof_simplify(const std::shared_ptr< SymbolicExpr > &rootof_expr)
static CalculusRealCandidateStatus calculus_utils_extract_real_candidate(const std::shared_ptr< SymbolicExpr > &candidate, std::shared_ptr< SymbolicExpr > &real_candidate, ComputationContext &context)
static SymbolicExprVectorResult explicit_inverse_candidates(const FiniteSolutions &finite, const std::string &operation)
SymbolicExprVectorResult inverse_function_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::shared_ptr< SymbolicExpr > &y, ComputationContext &context)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
static bool is_nonreal_sqrt(const FunctionNode &function, ComputationContext &context)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
LMCAS::SolveResult solve_equation(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::vector< FiniteSolution > values
static bool any_nonreal_sqrt(const std::vector< std::shared_ptr< const SymbolicNode > > &children, ComputationContext &context)
Result< std::vector< std::shared_ptr< SymbolicExpr > > > SymbolicExprVectorResult
ExpressionResult inverse_derivative_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::shared_ptr< SymbolicExpr > &point, ComputationContext &context)
ExprResult complex(ExprPtr real, ExprPtr imag)
static bool contains_inverse_candidate(const std::vector< std::shared_ptr< SymbolicExpr > > &candidates, const std::shared_ptr< SymbolicExpr > &candidate)
ExprPtr imag
static ExpressionResult inverse_branch_derivative(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::vector< std::shared_ptr< SymbolicExpr > > &candidates, const std::string &operation, ComputationContext &context)
static SymbolicExprVectorResult verified_real_inverse_candidates(const std::vector< std::shared_ptr< SymbolicExpr > > &candidates, const std::shared_ptr< SymbolicExpr > &equation, const std::string &var, const std::string &operation, ComputationContext &context)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
static bool calculus_utils_contains_nonreal_sqrt(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context)
static bool calculus_utils_is_negative_number(const std::shared_ptr< const NumberNode > &number)
static bool calculus_utils_contains_complex(const std::shared_ptr< const SymbolicNode > &node)
方程求解选项,控制数值求解行为和结果形式.
RootOf 恒等关系、求值及代数闭式化简。
方程求解策略调度器 solve_dispatch 及相关选项结构体.
内部 AST 定义。