LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inference_engine_periodicity.cpp
浏览该文件的文档.
7#include <limits>
8
9namespace LMCAS {
10namespace {
11constexpr const char* periodic_operation = "inference.periodic";
12using Node = std::shared_ptr<const SymbolicNode>;
13
16 std::optional<SymbolicExpr> period;
17 bool real_valued = false;
18};
19
21public:
22 PeriodInference(const AssumptionContext& assumptions, const InferenceEngine& engine,
23 const std::string& variable, ComputationContext& context)
24 : assumptions_(assumptions), facts_(engine), variable_(variable), context_(context),
25 max_depth_(engine.get_max_depth()) {}
26
28 auto entered = context_.enter_recursion(periodic_operation);
29 if (!entered) { return Result<PeriodEvidence>::failure(entered.error()); }
30 struct Leave {
32 ~Leave() { context.leave_recursion(); }
33 } leave{context_};
34 if (depth_ >= max_depth_) return PeriodEvidence{};
35 ++depth_;
36 struct LeaveProof {
37 int& depth;
38 ~LeaveProof() { --depth; }
39 } leave_proof{depth_};
40
41 if (const auto* symbol = dynamic_cast<const VariableNode*>(node.get())) {
42 if (!symbol->is_constant() &&
43 assumptions_.has_period_declarations(symbol->name())) {
44 return declared_period(node, *symbol);
45 }
46 }
47 auto constant_real = real_defined(node);
48 if (!constant_real) { return Result<PeriodEvidence>::failure(constant_real.error()); }
49 if (constant_real.value() == Tribool::True && independent(node))
50 { return PeriodEvidence{Tribool::True, std::nullopt, true}; }
51
52 return function_period(node);
53 }
54
55private:
57 const auto* function = dynamic_cast<const FunctionNode*>(node.get());
58 if (!function) { return PeriodEvidence{}; }
60 { return PeriodEvidence{Tribool::False, std::nullopt, false}; }
61 if (function->arguments().size() != 1) { return PeriodEvidence{}; }
62 const Node& argument = function->arguments().front();
64 return arctangent_period(argument);
65 }
66 const auto type = function->type();
68 type != FunctionNode::FuncType::Tan) { return PeriodEvidence{}; }
69 return affine_period(node, argument, type);
70 }
71
73 auto period = assumptions_.get_period(symbol.name(), variable_);
74 if (!period) { return PeriodEvidence{}; }
75 auto defined = detail::query_definedness(
77 if (!defined) { return Result<PeriodEvidence>::failure(defined.error()); }
78 auto positive = detail::query_positive_value(
79 detail::node(*period), facts_, context_);
80 if (!positive) { return Result<PeriodEvidence>::failure(positive.error()); }
81 if (defined.value() != Tribool::True || positive.value() != Tribool::True ||
82 !independent(detail::node(*period)))
83 { return PeriodEvidence{}; }
86 return PeriodEvidence{
87 Tribool::True, *period, real.value() == Tribool::True};
88 }
89
91 const auto* symbol = dynamic_cast<const VariableNode*>(argument.get());
92 if (symbol && !symbol->is_constant() && symbol->name() == variable_ &&
93 !assumptions_.has_period_declarations(symbol->name())) {
94 return PeriodEvidence{Tribool::False, std::nullopt, true};
95 }
96 auto inner = infer(argument);
97 if (!inner) { return inner; }
98 if (inner.value().periodic == Tribool::True && inner.value().real_valued)
99 { return inner; }
100 return PeriodEvidence{};
101 }
102
104 auto defined = detail::query_definedness(argument, facts_, Domain::Real, context_);
105 if (!defined) { return Result<PeriodEvidence>::failure(defined.error()); }
106 if (defined.value() != Tribool::True) { return PeriodEvidence{}; }
108 if (!affine) { return Result<PeriodEvidence>::failure(affine.error()); }
109 if (!affine.value()) { return PeriodEvidence{}; }
110 for (auto* coefficient : {&affine.value()->slope, &affine.value()->offset}) {
111 auto normalized = detail::simplify_expression(*coefficient, context_);
112 if (!normalized) { return Result<PeriodEvidence>::failure(normalized.error()); }
113 *coefficient = std::move(normalized.value());
114 }
115 const auto& slope = affine.value()->slope;
116 const auto& offset = affine.value()->offset;
117 for (const auto& coefficient : {slope, offset}) {
118 auto real = real_defined(detail::node(*coefficient));
120 if (real.value() != Tribool::True || !independent(detail::node(*coefficient)))
121 { return PeriodEvidence{}; }
122 }
124 if (!nonzero) { return Result<PeriodEvidence>::failure(nonzero.error()); }
125 return period_from_slope(node, type, slope, nonzero.value());
126 }
127
128 Result<PeriodEvidence> period_from_slope(const Node& node, FunctionNode::FuncType type, const std::shared_ptr<SymbolicExpr>& slope, Tribool nonzero) {
129 if (nonzero == Tribool::False) {
130 auto constant_domain = detail::query_definedness(node, facts_, Domain::Real, context_);
131 if (!constant_domain) { return Result<PeriodEvidence>::failure(constant_domain.error()); }
132 if (constant_domain.value() == Tribool::True)
133 { return PeriodEvidence{Tribool::True, std::nullopt, true}; }
134 return PeriodEvidence{};
135 }
136 if (nonzero != Tribool::True) { return PeriodEvidence{}; }
137 auto positive = detail::query_positive_value(detail::node(*slope), facts_, context_);
138 if (!positive) { return Result<PeriodEvidence>::failure(positive.error()); }
139 std::shared_ptr<SymbolicExpr> magnitude;
140 if (positive.value() == Tribool::True) {
141 magnitude = slope;
142 } else if (positive.value() == Tribool::False) {
143 magnitude = SymbolicExpr::multiply(SymbolicExpr::number(-1), slope);
144 } else {
146 FunctionNode::FuncType::Abs, std::vector<Node>{detail::node(*slope)}));
147 }
148 auto exact_pi = detail::constant_expression("pi");
149 if (!exact_pi) { return Result<PeriodEvidence>::failure(exact_pi.error()); }
150 auto numerator = type == FunctionNode::FuncType::Tan ? exact_pi.value() :
151 SymbolicExpr::multiply(SymbolicExpr::number(2), exact_pi.value());
152 auto period = detail::simplify_expression(SymbolicExpr::divide(numerator, magnitude), context_);
153 if (!period) { return Result<PeriodEvidence>::failure(period.error()); }
154 return PeriodEvidence{Tribool::True, *period.value(), true};
155 }
156
157 bool independent(const Node& node) const {
158 detail::RewriteBudget budget(context_, context_.limits().max_recursion_depth,
159 std::numeric_limits<std::size_t>::max(), periodic_operation);
160 const auto names = free_variables(node, &budget);
161 for (const auto& name : names) {
162 auto step = context_.consume_steps(1, periodic_operation);
163 if (!step) throw step.error();
164 if (name == variable_ || assumptions_.has_period_declarations(name)) return false;
165 }
166 return true;
167 }
168
169 Result<Tribool> real_defined(const Node& node) const {
171 if (!defined || defined.value() != Tribool::True) return defined;
173 }
174
175 const AssumptionContext& assumptions_;
177 const std::string& variable_;
179 const int max_depth_;
180 int depth_ = 0;
181};
182
184 const SymbolicExpr& expression, const std::string& variable,
185 const AssumptionContext& assumptions, const InferenceEngine& engine,
187 if (variable.empty()) {
189 "independent variable must not be empty", periodic_operation);
190 }
192 [&]() -> Result<PeriodEvidence> {
193 PeriodInference inference(assumptions, engine, variable, context);
194 return inference.infer(detail::node(expression));
195 });
196}
197}
198
199InferenceTriboolResult InferenceEngine::query_periodic_checked(
200 const SymbolicExpr& expression, const std::string& variable) const {
201 ComputationContext context;
202 return query_periodic_checked(expression, variable, context);
203}
204
205InferenceTriboolResult InferenceEngine::query_periodic_checked(
206 const SymbolicExpr& expression, const std::string& variable, ComputationContext& context) const {
207 auto proof = periodicity_checked(expression, variable, impl_->ctx, *this, context);
208 if (!proof) return InferenceTriboolResult::failure(proof.error());
209 return proof.value().periodic;
210}
211
212InferencePeriodResult InferenceEngine::infer_period_checked(
213 const SymbolicExpr& expression, const std::string& variable) const {
215 return infer_period_checked(expression, variable, context);
216}
217
218InferencePeriodResult InferenceEngine::infer_period_checked(
219 const SymbolicExpr& expression, const std::string& variable, ComputationContext& context) const {
220 auto proof = periodicity_checked(expression, variable, impl_->ctx, *this, context);
221 if (!proof) return InferencePeriodResult::failure(proof.error());
222 return std::move(proof.value().period);
223}
224
225}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
变量节点,表示一个符号变量。
const std::string & name() const noexcept
Result< PeriodEvidence > period_from_slope(const Node &node, FunctionNode::FuncType type, const std::shared_ptr< SymbolicExpr > &slope, Tribool nonzero)
Result< PeriodEvidence > affine_period(const Node &node, const Node &argument, FunctionNode::FuncType type)
PeriodInference(const AssumptionContext &assumptions, const InferenceEngine &engine, const std::string &variable, ComputationContext &context)
Result< PeriodEvidence > declared_period(const Node &node, const VariableNode &symbol)
Result< PeriodEvidence > periodicity_checked(const SymbolicExpr &expression, const std::string &variable, const AssumptionContext &assumptions, const InferenceEngine &engine, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ExpressionResult constant_expression(const char *name)
ExpressionResult simplify_expression(const ExprPtr &expression, ComputationContext &context)
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_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< std::optional< AffineForm > > recognize_affine(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
Result< T > checked_inference_result(const SymbolicExpr &expr, const std::string &operation, ComputationContext &context, const std::function< Result< T >()> &query)
@ Real
Real numbers
Result< std::optional< SymbolicExpr > > InferencePeriodResult
Tribool
Tri-state logic value for property queries.
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
std::size_t std::size_t depth
std::set< std::string > free_variables(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget)
Result< Tribool > InferenceTriboolResult
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name