LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inference_engine_functions.cpp
浏览该文件的文档.
1#define _USE_MATH_DEFINES
4#include <type_traits>
5
6namespace LMCAS {
7
9 const InferenceEngine& engine, const SymbolicNode& node, ComputationContext& context) {
10 const detail::AssumptionFacts facts(engine);
11 const std::shared_ptr<const SymbolicNode> borrowed(
12 std::shared_ptr<const SymbolicNode>{}, &node);
13 bool violated_real_restriction = false;
14 auto defined = detail::query_definedness(
15 borrowed, facts, Domain::Real, context, &violated_real_restriction);
16 if (defined && defined.value() == Tribool::False) {
17 if (!violated_real_restriction) {
18 auto complex_defined =
20 if (!complex_defined) return InferenceTriboolResult::failure(complex_defined.error());
21 if (complex_defined.value() != Tribool::False) {
22 auto real_value = detail::query_real_value(borrowed, facts, context);
23 if (!real_value) return InferenceTriboolResult::failure(real_value.error());
24 if (real_value.value() == Tribool::Unknown) return Tribool::Unknown;
25 }
26 }
28 CasErrc::DomainError, "expression is undefined in the real domain",
29 "inference.definedness");
30 }
31 return defined;
32}
33
35 const InferenceEngine& engine,
36 const SymbolicExpr& arg_expr,
38 const detail::AssumptionFacts facts(engine);
39 auto real = detail::query_real_value(detail::node(arg_expr), facts, context);
40 if (!real) {
41 return real;
42 }
43 if (real.value() == Tribool::True) {
44 return known_sign(1, target);
45 }
46 return Tribool::Unknown;
47}
48
50 const InferenceEngine& engine,
51 const SymbolicExpr& arg_expr, ComputationContext& context) const {
52 auto real = engine.query_domain_of_checked(arg_expr, Domain::Real, context);
53 if (!real) {
54 return real;
55 }
56 return Tribool::Unknown;
57}
58
60 const InferenceEngine& engine,
61 const SymbolicExpr& arg_expr,
63 auto arg_real_result = engine.query_domain_of_checked(arg_expr, Domain::Real, context);
64 if (!arg_real_result) {
65 return arg_real_result;
66 }
67 const Tribool arg_real = arg_real_result.value();
68 if (arg_real != Tribool::True) {
70 }
71
72 auto arg_pos_result = engine.query_sign_of_checked(arg_expr, Sign::Positive, context);
73 if (!arg_pos_result) {
74 return arg_pos_result;
75 }
76 const Tribool arg_pos = arg_pos_result.value();
77 auto arg_neg_result = engine.query_sign_of_checked(arg_expr, Sign::Negative, context);
78 if (!arg_neg_result) {
79 return arg_neg_result;
80 }
81 const Tribool arg_neg = arg_neg_result.value();
82 auto arg_nz_result = engine.query_sign_of_checked(arg_expr, Sign::NonZero, context);
83 if (!arg_nz_result) {
84 return arg_nz_result;
85 }
86 const Tribool arg_nz = arg_nz_result.value();
87 bool abs_is_positive = (arg_pos == Tribool::True) ||
88 (arg_neg == Tribool::True) ||
89 (arg_nz == Tribool::True);
90
91 if (abs_is_positive) {
92 return known_sign(1, target);
93 }
95}
96
98 const InferenceEngine&,
99 const SymbolicExpr& arg_expr,
101 if (const auto* number = dynamic_cast<const NumberNode*>(detail::node(arg_expr).get())) {
102 const int sign = std::visit([](const auto& value) {
103 using T = std::decay_t<decltype(value)>;
104 return value > T(1) ? 1 : value < T(1) ? -1 : 0;
105 }, number->value());
106 return known_sign(sign, target);
107 }
108 auto step = context.consume_steps(1, "inference.logarithm");
109 if (!step) {
110 return InferenceTriboolResult::failure(step.error());
111 }
113 auto greater = ctx.has_relation_checked(arg_expr, one, RelationOp::GT, context);
114 if (!greater) {
115 return InferenceTriboolResult::failure(greater.error());
116 }
117 if (greater.value()) {
118 return known_sign(1, target);
119 }
120 auto equal = ctx.has_relation_checked(arg_expr, one, RelationOp::EQ, context);
121 if (!equal) {
122 return InferenceTriboolResult::failure(equal.error());
123 }
124 if (equal.value()) {
125 return known_sign(0, target);
126 }
127 auto less = ctx.has_relation_checked(arg_expr, one, RelationOp::LT, context);
128 if (!less) {
129 return InferenceTriboolResult::failure(less.error());
130 }
131 if (less.value()) {
132 return known_sign(-1, target);
133 }
134 return Tribool::Unknown;
135}
136
138 const InferenceEngine& engine,
139 const SymbolicExpr& arg_expr,
141 auto nonnegative = engine.query_sign_of_checked(arg_expr, Sign::NonNegative, context);
142 if (!nonnegative) {
143 return nonnegative;
144 }
145 if (nonnegative.value() == Tribool::True) {
146 return nonnegative_sign(target);
147 }
148 return Tribool::Unknown;
149}
150
152 const InferenceEngine& engine,
153 const SymbolicExpr& arg_expr, ComputationContext& context) const {
154 auto arg_real_result = engine.query_real_checked(arg_expr, context);
155 if (!arg_real_result) {
156 return arg_real_result;
157 }
158 const Tribool arg_real = arg_real_result.value();
159 if (arg_real == Tribool::True) {
161 }
162
163 auto arg_int_result = engine.query_integer_checked(arg_expr, context);
164 if (!arg_int_result) {
165 return arg_int_result;
166 }
167 const Tribool arg_int = arg_int_result.value();
168 if (arg_int == Tribool::True) {
170 }
172}
173
175 const InferenceEngine& engine,
176 const SymbolicExpr& arg_expr,
178 if (target != Domain::Real) {
179 return Tribool::Unknown;
180 }
181 const detail::AssumptionFacts facts(engine);
182 auto real = detail::query_real_value(detail::node(arg_expr), facts, context);
183 if (!real) return real;
185}
186
188 const InferenceEngine& engine,
189 const SymbolicExpr& arg_expr,
191 if (target == Domain::Real) {
192 return real_or_integer(engine, arg_expr, context);
193 }
194 if (target == Domain::Integer) {
195 auto integer = engine.query_integer_checked(arg_expr, context);
196 if (!integer) {
197 return integer;
198 }
199 if (integer.value() == Tribool::True) {
200 return Tribool::True;
201 }
202 }
203 return Tribool::Unknown;
204}
205
207 const InferenceEngine& engine,
208 const SymbolicExpr& arg_expr,
210 if (target != Domain::Real) return Tribool::Unknown;
211 const detail::AssumptionFacts facts(engine);
212 auto positive = detail::query_positive_value(detail::node(arg_expr), facts, context);
213 if (!positive) return positive;
214 return positive.value() == Tribool::True ? Tribool::True : Tribool::Unknown;
215}
216
218 const InferenceEngine& engine,
219 const SymbolicExpr& arg_expr,
221 if (target == Domain::Real) {
222 auto arg_nonneg_result = engine.query_sign_of_checked(arg_expr, Sign::NonNegative, context);
223 if (!arg_nonneg_result) {
224 return arg_nonneg_result;
225 }
226 const Tribool arg_nonneg = arg_nonneg_result.value();
227 if (arg_nonneg == Tribool::True) {
229 }
230 }
232}
233
235 const InferenceEngine& engine,
236 const SymbolicExpr& arg_expr,
238 if (target == Domain::Real) {
239 auto arg_real_result = engine.query_real_checked(arg_expr, context);
240 if (!arg_real_result) {
241 return arg_real_result;
242 }
243 const Tribool arg_real = arg_real_result.value();
244 if (arg_real == Tribool::True) {
246 }
247 }
249}
250
251InferenceTriboolResult InferenceEngine::infer_function_property_checked(
252 const FunctionNode& node, Sign target, ComputationContext& context) const {
253 try {
254 if (node.arguments().empty()) {
256 }
257 if (node.type() == FunctionNode::FuncType::Ln ||
258 node.type() == FunctionNode::FuncType::Exp) {
259 auto defined = Impl::real_definedness(*this, node, context);
260 if (!defined || defined.value() != Tribool::True) { return defined; }
261 }
262
263 auto arg_expr = LMCAS::detail::expression_from_node(node.arguments()[0]);
264 return impl_->function_sign(*this, node.type(), arg_expr, target, context);
265 } catch (const CasError& error) {
267 } catch (const std::bad_alloc&) {
270 "function sign inference allocation failed",
271 "infer_function_property_checked");
272 } catch (const std::exception& ex) {
275 ex.what(),
276 "infer_function_property_checked");
277 }
278}
279
281 const InferenceEngine& engine, FunctionNode::FuncType type,
282 const SymbolicExpr& arg_expr, Sign target, ComputationContext& context) const {
283 switch (type) {
285 return exponential_sign(engine, arg_expr, target, context);
286 }
290 return trigonometric_sign(engine, arg_expr, context);
291 }
293 return absolute_sign(engine, arg_expr, target, context);
294 }
296 return logarithm_sign(engine, arg_expr, target, context);
297 }
299 return square_root_sign(engine, arg_expr, target, context);
300 }
302 return engine.query_sign_of_checked(arg_expr, target, context);
303 }
304 default:
306 }
307}
308
309InferenceTriboolResult InferenceEngine::infer_function_domain_checked(
310 const FunctionNode& node, Domain target, ComputationContext& context) const {
311 try {
312 if (node.arguments().empty()) {
314 }
315 if (node.type() == FunctionNode::FuncType::Ln ||
316 node.type() == FunctionNode::FuncType::Exp) {
317 auto defined = Impl::real_definedness(*this, node, context);
318 if (!defined || defined.value() != Tribool::True) { return defined; }
319 }
320
321 auto arg_expr = LMCAS::detail::expression_from_node(node.arguments()[0]);
322 return impl_->function_domain(*this, node.type(), arg_expr, target, context);
323 } catch (const CasError& error) {
325 } catch (const std::bad_alloc&) {
328 "function domain inference allocation failed",
329 "infer_function_domain_checked");
330 } catch (const std::exception& ex) {
333 ex.what(),
334 "infer_function_domain_checked");
335 }
336}
337
339 const InferenceEngine& engine, FunctionNode::FuncType type,
340 const SymbolicExpr& arg_expr, Domain target, ComputationContext& context) const {
341 switch (type) {
343 return exponential_domain(engine, arg_expr, target, context);
344 }
348 if (target == Domain::Real) {
349 return real_or_integer(engine, arg_expr, context);
350 }
352 }
354 return absolute_domain(engine, arg_expr, target, context);
355 }
357 return logarithm_domain(engine, arg_expr, target, context);
358 }
360 return square_root_domain(engine, arg_expr, target, context);
361 }
363 return arctangent_domain(engine, arg_expr, target, context);
364 }
365 default:
367 }
368}
369
370}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sqrt
对数、绝对值、平方根。
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(Tribool value)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
std::shared_ptr< const Node > make_node(Args &&... args)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
ExprResult real(const ExprPtr &expression, ComputationContext &context)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Complex
Complex numbers (default, least specific)
@ Real
Real numbers
Tribool
Tri-state logic value for property queries.
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
const ExprPtr & target
const std::string const ExprPtr & value
Result< Tribool > InferenceTriboolResult
Sign
Sign classification for symbols and expressions.
InferenceTriboolResult real_or_integer(const InferenceEngine &engine, const SymbolicExpr &arg_expr, ComputationContext &context) const
InferenceTriboolResult exponential_domain(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Domain target, ComputationContext &context) const
InferenceTriboolResult trigonometric_sign(const InferenceEngine &engine, const SymbolicExpr &arg_expr, ComputationContext &context) const
InferenceTriboolResult square_root_sign(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Sign target, ComputationContext &context) const
static InferenceTriboolResult real_definedness(const InferenceEngine &engine, const SymbolicNode &node, ComputationContext &context)
InferenceTriboolResult exponential_sign(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Sign target, ComputationContext &context) const
InferenceTriboolResult arctangent_domain(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Domain target, ComputationContext &context) const
InferenceTriboolResult square_root_domain(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Domain target, ComputationContext &context) const
static Tribool known_sign(int value, Sign target)
InferenceTriboolResult absolute_domain(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Domain target, ComputationContext &context) const
InferenceTriboolResult function_sign(const InferenceEngine &engine, FunctionNode::FuncType type, const SymbolicExpr &argument, Sign target, ComputationContext &context) const
InferenceTriboolResult absolute_sign(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Sign target, ComputationContext &context) const
InferenceTriboolResult function_domain(const InferenceEngine &engine, FunctionNode::FuncType type, const SymbolicExpr &argument, Domain target, ComputationContext &context) const
InferenceTriboolResult logarithm_sign(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Sign target, ComputationContext &context) const
InferenceTriboolResult logarithm_domain(const InferenceEngine &engine, const SymbolicExpr &arg_expr, Domain target, ComputationContext &context) const