LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inference_engine_product.cpp
浏览该文件的文档.
1#define _USE_MATH_DEFINES
4#include <cstdint>
5
6namespace LMCAS {
7namespace {
8constexpr std::uint8_t negative_sign = 1;
9constexpr std::uint8_t zero_sign = 2;
10constexpr std::uint8_t positive_sign = 4;
11constexpr std::uint8_t all_signs = 7;
12
13std::uint8_t sign_set(Sign target) {
14 switch (target) {
15 case Sign::Positive: return positive_sign;
16 case Sign::Negative: return negative_sign;
17 case Sign::Zero: return zero_sign;
21 default: return all_signs;
22 }
23}
24
25std::uint8_t multiply_sign_sets(std::uint8_t left, std::uint8_t right) {
26 std::uint8_t result = 0;
27 for (std::uint8_t a : {negative_sign, zero_sign, positive_sign}) {
28 for (std::uint8_t b : {negative_sign, zero_sign, positive_sign}) {
29 if (!(left & a) || !(right & b)) continue;
30 result |= a == zero_sign || b == zero_sign ? zero_sign :
32 }
33 }
34 return result;
35}
36}
37
39 const InferenceEngine& engine,
40 const std::shared_ptr<const SymbolicNode>& operand,
41 std::uint8_t& possible, ComputationContext& context) const {
42 const auto expression = detail::expression_from_node(operand);
43 std::uint8_t operand_signs = all_signs;
46 auto fact = engine.query_sign_of_checked(expression, sign, context);
47 if (!fact) return fact;
48 if (fact.value() == Tribool::True) operand_signs &= sign_set(sign);
49 }
50 possible = multiply_sign_sets(possible, operand_signs);
51 return Tribool::True;
52}
53
55 std::uint8_t possible, Sign target) {
56 if (!possible) return Tribool::Unknown;
57 const auto wanted = sign_set(target);
58 if ((possible & wanted) == possible) return Tribool::True;
59 if (!(possible & wanted)) return Tribool::False;
60 return Tribool::Unknown;
61}
62
64 const InferenceEngine& engine, const MultiplyNode& node, Sign target, ComputationContext& context) const {
65 auto defined = real_definedness(engine, node, context);
66 if (!defined || defined.value() != Tribool::True) { return defined; }
67 const detail::AssumptionFacts facts(engine);
68 bool all_real = true;
69 for (const auto& operand : node.operands()) {
70 auto real = detail::query_real_value(operand, facts, context);
71 if (!real) { return real; }
72 all_real = all_real && real.value() == Tribool::True;
73 }
74 if (!all_real) { return Tribool::Unknown; }
75 std::uint8_t possible = positive_sign;
76 for (const auto& operand : node.operands()) {
77 auto result = accumulate_product_sign(engine, operand, possible, context);
78 if (!result) { return result; }
79 }
80 return product_parity_sign(possible, target);
81}
82
84 const InferenceEngine& engine, const SymbolicExpr& numerator,
85 const SymbolicExpr& denominator, Sign target, ComputationContext& context) const {
86 const detail::AssumptionFacts facts(engine);
87 bool all_defined = true;
88 bool all_real = true;
89 for (const auto* expression : {&numerator, &denominator}) {
90 auto defined = real_definedness(engine, *detail::node(*expression), context);
91 if (!defined) { return defined; }
92 all_defined = all_defined && defined.value() == Tribool::True;
93 auto real = detail::query_real_value(detail::node(*expression), facts, context);
94 if (!real) { return real; }
95 all_real = all_real && real.value() == Tribool::True;
96 }
98 if (!nonzero) { return nonzero; }
99 if (nonzero.value() == Tribool::False) {
101 CasErrc::DomainError, "division denominator is zero", "inference.division");
102 }
103 if (!all_defined || !all_real || nonzero.value() != Tribool::True)
104 { return Tribool::Unknown; }
105 std::uint8_t possible = positive_sign;
106 auto first = accumulate_product_sign(engine, detail::node(numerator), possible, context);
107 if (!first) { return first; }
108 auto second = accumulate_product_sign(engine, detail::node(denominator), possible, context);
109 if (!second) { return second; }
110 return product_parity_sign(possible, target);
111}
112
113InferenceTriboolResult InferenceEngine::infer_division_sign_checked(
114 const MultiplyNode& node, Sign target, ComputationContext& context) const {
115 try {
116 if (node.operands().size() != 2) {
117 return Tribool::Unknown;
118 }
119 std::shared_ptr<const SymbolicNode> numerator;
120 std::shared_ptr<const SymbolicNode> denominator;
121 for (const auto& operand : node.operands()) {
122 auto step = context.consume_steps(1, "inference.product");
123 if (!step) {
124 throw step.error();
125 }
126 const auto power = std::dynamic_pointer_cast<const PowerNode>(operand);
127 const auto exponent = power
128 ? std::dynamic_pointer_cast<const NumberNode>(
129 power->exponent())
130 : nullptr;
131 if (exponent && exponent->is_negative_one() && !denominator) {
132 denominator = power->base();
133 } else {
134 numerator = operand;
135 }
136 }
137 if (!numerator || !denominator) {
138 return Tribool::Unknown;
139 }
140 return impl_->quotient_sign(*this, detail::expression_from_node(numerator),
142 } catch (const CasError& error) {
144 } catch (const std::bad_alloc&) {
146 "division sign inference allocation failed", "infer_division_sign_checked");
147 } catch (const std::exception& ex) {
149 ex.what(), "infer_division_sign_checked");
150 }
151}
152
153InferenceTriboolResult InferenceEngine::infer_multiply_sign_checked(
154 const MultiplyNode& node, Sign target, ComputationContext& context) const {
155 try {
156 if (node.operands().size() == 2) {
157 for (const auto& operand : node.operands()) {
158 auto step = context.consume_steps(1, "inference.product");
159 if (!step) throw step.error();
160 const auto power =
161 std::dynamic_pointer_cast<const PowerNode>(operand);
162 const auto exponent = power
163 ? std::dynamic_pointer_cast<const NumberNode>(
164 power->exponent())
165 : nullptr;
166 if (exponent && exponent->is_negative_one())
167 return infer_division_sign_checked(node, target, context);
168 }
169 }
170 return impl_->product_sign(*this, node, target, context);
171 } catch (const CasError& error) {
173 } catch (const std::bad_alloc&) {
175 "multiplication sign inference allocation failed", "infer_multiply_sign_checked");
176 } catch (const std::exception& ex) {
178 ex.what(), "infer_multiply_sign_checked");
179 }
180}
181
182}
乘法节点,表示多个操作数的乘积。
static Result failure(CasErrc code, std::string message, std::string operation={})
std::uint8_t multiply_sign_sets(std::uint8_t left, std::uint8_t right)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
const MultiPoly & b
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
const ExprPtr & target
const ExprPtr & right
Result< Tribool > InferenceTriboolResult
const ExprPtr & denominator
Sign
Sign classification for symbols and expressions.
InferenceTriboolResult quotient_sign(const InferenceEngine &engine, const SymbolicExpr &num_expr, const SymbolicExpr &den_expr, Sign target, ComputationContext &context) const
static InferenceTriboolResult product_parity_sign(std::uint8_t possible, Sign target)
static InferenceTriboolResult real_definedness(const InferenceEngine &engine, const SymbolicNode &node, ComputationContext &context)
InferenceTriboolResult accumulate_product_sign(const InferenceEngine &engine, const std::shared_ptr< const SymbolicNode > &operand, std::uint8_t &possible, ComputationContext &context) const
InferenceTriboolResult product_sign(const InferenceEngine &engine, const MultiplyNode &node, Sign target, ComputationContext &context) const