LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inference_engine_arithmetic.cpp
浏览该文件的文档.
1#define _USE_MATH_DEFINES
3
4namespace LMCAS {
5
7 switch (target) {
8 case Sign::Positive: {
10 }
11 case Sign::Negative: {
12 return value < 0 ? Tribool::True : Tribool::False;
13 }
14 case Sign::NonNegative: {
15 return value >= 0 ? Tribool::True : Tribool::False;
16 }
17 case Sign::NonPositive: {
18 return value <= 0 ? Tribool::True : Tribool::False;
19 }
20 case Sign::Zero: {
21 return value == 0 ? Tribool::True : Tribool::False;
22 }
23 case Sign::NonZero: {
24 return value != 0 ? Tribool::True : Tribool::False;
25 }
26 }
27 return Tribool::Unknown;
28}
29
39
40std::shared_ptr<const SymbolicNode> InferenceEngine::Impl::subtrahend(
41 const std::shared_ptr<const SymbolicNode>& operand, ComputationContext& context) {
42 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(operand);
43 if (!mul || mul->operands().size() != 2) {
44 return nullptr;
45 }
46 bool found_neg_one = false;
47 std::shared_ptr<const SymbolicNode> other_operand;
48 for (const auto& mul_op : mul->operands()) {
49 auto step = context.consume_steps(1, "inference.arithmetic");
50 if (!step) throw step.error();
51 const auto number =
52 std::dynamic_pointer_cast<const NumberNode>(mul_op);
53 if (number && number->is_negative_one()) {
54 found_neg_one = true;
55 continue;
56 }
57 other_operand = mul_op;
58 }
59 return found_neg_one ? other_operand : nullptr;
60}
61
63 if (node.operands().size() != 2) {
64 return false;
65 }
66 for (const auto& operand : node.operands()) {
67 auto step = context.consume_steps(1, "inference.arithmetic");
68 if (!step) throw step.error();
69 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(operand);
70 if (!mul || mul->operands().size() != 2) {
71 continue;
72 }
73 for (const auto& factor : mul->operands()) {
74 auto step = context.consume_steps(1, "inference.arithmetic");
75 if (!step) throw step.error();
76 const auto number =
77 std::dynamic_pointer_cast<const NumberNode>(factor);
78 if (number && number->is_negative_one()) {
79 return true;
80 }
81 }
82 }
83 return false;
84}
85
87 const InferenceEngine& engine,
88 const AddNode& node,
90 bool all_have_property = true;
91
92 for (const auto& operand : node.operands()) {
93 auto step = context.consume_steps(1, "inference.arithmetic");
94 if (!step) throw step.error();
95 auto op_expr = LMCAS::detail::expression_from_node(operand);
96 Tribool op_result = Tribool::Unknown;
100 }
101 auto queried = engine.query_sign_of_checked(op_expr, target, context);
102 if (!queried) {
103 return queried;
104 }
105 op_result = queried.value();
106
107 if (op_result == Tribool::Unknown) {
109 }
110 if (op_result == Tribool::False) {
111 all_have_property = false;
112 }
113 }
114
115 if (all_have_property) {
117 }
118
120}
121
123 const InferenceEngine& engine,
124 const SymbolicExpr& minuend_expr,
125 const SymbolicExpr& subtrahend_expr,
127 auto min_pos_result =
128 engine.query_sign_of_checked(minuend_expr, Sign::Positive, context);
129 if (!min_pos_result) {
130 return min_pos_result;
131 }
132 const Tribool min_pos = min_pos_result.value();
133 auto min_neg_result =
134 engine.query_sign_of_checked(minuend_expr, Sign::Negative, context);
135 if (!min_neg_result) {
136 return min_neg_result;
137 }
138 const Tribool min_neg = min_neg_result.value();
139 auto sub_pos_result =
140 engine.query_sign_of_checked(subtrahend_expr, Sign::Positive, context);
141 if (!sub_pos_result) {
142 return sub_pos_result;
143 }
144 const Tribool sub_pos = sub_pos_result.value();
145 auto sub_neg_result =
146 engine.query_sign_of_checked(subtrahend_expr, Sign::Negative, context);
147 if (!sub_neg_result) {
148 return sub_neg_result;
149 }
150 const Tribool sub_neg = sub_neg_result.value();
151
152 if (min_pos == Tribool::True && sub_neg == Tribool::True) {
153 return known_sign(1, target);
154 }
155
156 if (min_neg == Tribool::True && sub_pos == Tribool::True) {
157 return known_sign(-1, target);
158 }
159
160 return weak_subtraction_sign(engine, minuend_expr, subtrahend_expr, target, context);
161}
162
164 const InferenceEngine& engine,
165 const SymbolicExpr& minuend_expr,
166 const SymbolicExpr& subtrahend_expr,
168 auto min_nn_result =
169 engine.query_sign_of_checked(minuend_expr, Sign::NonNegative, context);
170 if (!min_nn_result) {
171 return min_nn_result;
172 }
173 const Tribool min_nn = min_nn_result.value();
174 auto sub_np_result =
175 engine.query_sign_of_checked(subtrahend_expr, Sign::NonPositive, context);
176 if (!sub_np_result) {
177 return sub_np_result;
178 }
179 const Tribool sub_np = sub_np_result.value();
180 if (min_nn == Tribool::True && sub_np == Tribool::True) {
181 switch (target) {
184 default: break;
185 }
186 }
187
188 auto min_np_result =
189 engine.query_sign_of_checked(minuend_expr, Sign::NonPositive, context);
190 if (!min_np_result) {
191 return min_np_result;
192 }
193 const Tribool min_np = min_np_result.value();
194 auto sub_nn_result =
195 engine.query_sign_of_checked(subtrahend_expr, Sign::NonNegative, context);
196 if (!sub_nn_result) {
197 return sub_nn_result;
198 }
199 const Tribool sub_nn = sub_nn_result.value();
200 if (min_np == Tribool::True && sub_nn == Tribool::True) {
201 switch (target) {
204 default: break;
205 }
206 }
207
209}
210
211InferenceTriboolResult InferenceEngine::infer_add_sign_checked(
212 const AddNode& node, Sign target, ComputationContext& context) const {
213 try {
214 if (node.operands().empty()) {
216 }
218 auto sub_result = infer_subtraction_sign_checked(node, target, context);
219 if (!sub_result) {
220 return sub_result;
221 }
222 if (sub_result.value() != Tribool::Unknown) {
223 return sub_result;
224 }
225 }
226
227 /**
228 * @brief 各加数均具备目标符号属性时,和也具备该属性。
229 * @note 含 Unknown 或已知异号加数时返回 Unknown。
230 */
231
232 return impl_->sum_sign(*this, node, target, context);
233 } catch (const CasError& error) {
235 } catch (const std::bad_alloc&) {
238 "addition sign inference allocation failed",
239 "infer_add_sign_checked");
240 } catch (const std::exception& ex) {
243 ex.what(),
244 "infer_add_sign_checked");
245 }
246}
247
248InferenceTriboolResult InferenceEngine::infer_subtraction_sign_checked(
249 const AddNode& node, Sign target, ComputationContext& context) const {
250 try {
251 if (node.operands().size() != 2) {
253 }
254
255 std::shared_ptr<const SymbolicNode> minuend_node;
256 std::shared_ptr<const SymbolicNode> subtrahend_node;
257
258 for (const auto& operand : node.operands()) {
259 auto step = context.consume_steps(1, "inference.arithmetic");
260 if (!step) throw step.error();
261 auto inner = Impl::subtrahend(operand, context);
262 if (inner) {
263 subtrahend_node = inner;
264 } else {
265 minuend_node = operand;
266 }
267 }
268
269 if (!minuend_node || !subtrahend_node) {
271 }
272
273 auto minuend_expr = LMCAS::detail::expression_from_node(minuend_node);
274 auto subtrahend_expr = LMCAS::detail::expression_from_node(subtrahend_node);
275
276 return impl_->subtraction_sign(*this, minuend_expr, subtrahend_expr, target, context);
277 } catch (const CasError& error) {
279 } catch (const std::bad_alloc&) {
282 "subtraction sign inference allocation failed",
283 "infer_subtraction_sign_checked");
284 } catch (const std::exception& ex) {
287 ex.what(),
288 "infer_subtraction_sign_checked");
289 }
290}
291
292} // namespace LMCAS
加法节点,表示多个操作数的求和。
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)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
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 weak_subtraction_sign(const InferenceEngine &engine, const SymbolicExpr &minuend_expr, const SymbolicExpr &subtrahend_expr, Sign target, ComputationContext &context) const
static std::shared_ptr< const SymbolicNode > subtrahend(const std::shared_ptr< const SymbolicNode > &operand, ComputationContext &context)
InferenceTriboolResult sum_sign(const InferenceEngine &engine, const AddNode &node, Sign target, ComputationContext &context) const
InferenceTriboolResult subtraction_sign(const InferenceEngine &engine, const SymbolicExpr &minuend_expr, const SymbolicExpr &subtrahend_expr, Sign target, ComputationContext &context) const
static bool has_negated_operand(const AddNode &node, ComputationContext &context)
static Tribool known_sign(int value, Sign target)