3#include <unordered_map>
11 using RecursiveSymbolicVisitor::RecursiveSymbolicVisitor;
31 return found !=
bound_.end() && found->second != 0;
37 ++
bound_[binder->bound_name];
39 auto found =
bound_.find(binder->bound_name);
40 if (--found->second == 0)
bound_.erase(found);
43 std::unordered_map<std::string_view, std::size_t>
bound_;
48 bool antiderivatives =
false)
81 using RecursiveSymbolicVisitor::RecursiveSymbolicVisitor;
85 if (!node.is_constant())
names.insert(node.name());
88 names.insert(node.index_var());
92 names.insert(node.index_var());
96 names.insert(node.variable());
100 names.insert(node.source_var());
104 names.insert(node.bound_var());
108 names.insert(node.element_var());
112 names.insert(node.variable());
121 if (expression) expression->
accept(collector);
122 return std::move(collector.
names);
125std::string
fresh_name(
const std::string& base, std::set<std::string>& occupied) {
126 for (std::size_t suffix = 1;; ++suffix) {
127 auto candidate = base +
"_" + std::to_string(suffix);
128 if (occupied.insert(candidate).second)
return candidate;
135 std::set<std::string> replacement_free,
147 bool changed =
false;
150 auto binder = node.index_var();
157 bool changed =
false;
160 auto binder = node.index_var();
167 bool changed =
false;
170 auto binder = node.variable();
177 bool changed =
false;
179 auto binder = node.source_var();
187 bool changed =
false;
189 auto binder = node.bound_var();
190 auto predicate =
rewrite_scoped(node.predicate(), binder, changed);
197 bool changed =
false;
199 auto binder = node.element_var();
200 auto predicate =
rewrite_scoped(node.predicate(), binder, changed);
206 bool changed =
false;
208 auto binder = node.variable();
211 body, binder,
point, node.direction())
222 if (binder ==
target_)
return original_body;
224 auto body = original_body;
245 if (
const auto*
integer = std::get_if<BigInt>(&number.
value())) {
248 if (
const auto*
rational = std::get_if<Rational>(&number.
value())) {
256 const auto number = std::dynamic_pointer_cast<const NumberNode>(
node);
262 const SymbolicExpr& expression,
const std::string&
variable,
268 return std::optional<AffineForm>{};
270 return AffineResult::failure(converted.error());
272 const auto& polynomial = converted.value();
273 if (polynomial.degree() > 1)
return std::optional<AffineForm>{};
275 polynomial.coeffs.size() > 1 ? polynomial.coeffs[1].val : SymbolicExpr::number(0),
276 polynomial.coeffs.empty() ? SymbolicExpr::number(0) : polynomial.coeffs[0].val}};
281 auto number = std::dynamic_pointer_cast<const NumberNode>(node);
282 if (!number)
return std::nullopt;
285 if (std::holds_alternative<BigInt>(number->value())) {
286 value = std::get<BigInt>(number->value());
287 }
else if (std::holds_alternative<Rational>(number->value())) {
288 const Rational&
rational = std::get<Rational>(number->value());
289 if (!
rational.is_integer())
return std::nullopt;
295 const auto exact =
value.try_to_int64();
296 if (!exact || *exact < min_value || *exact > max_value) {
299 return static_cast<int>(*exact);
309 return all_names(expression,
budget);
314 FreeVariableCollector collector(budget);
315 if (expression) expression->
accept(collector);
316 return std::move(collector.variables);
322 if (!expression ||
variable.empty())
return false;
323 FreeVariableFinder finder(
variable, budget);
324 expression->
accept(finder);
330 if (!expression ||
variable.empty())
return false;
332 expression->
accept(finder);
340 if (!expression)
return nullptr;
341 if (
variable.empty())
throw std::invalid_argument(
"substitution variable cannot be empty");
342 if (!replacement)
throw std::invalid_argument(
"substitution replacement cannot be null");
345 auto occupied = all_names(expression, budget);
346 auto replacement_names = all_names(replacement, budget);
347 occupied.insert(replacement_names.begin(), replacement_names.end());
350 FreeSubstitution substitution(
variable, replacement,
351 std::move(replacement_free),
352 std::move(occupied), budget);
353 return substitution.rewrite(expression);
const std::variant< BigInt, Rational > & value() const noexcept
连乘节点,表示符号有限/无限连乘 prod_{k=a}^{b} f(k).
求和节点,表示符号有限/无限求和 sum_{k=a}^{b} f(k).
static std::shared_ptr< const SymbolicNode > create_variable(const std::string &name)
virtual void accept(LMCAS::detail::SymbolicVisitor &visitor) const =0
void visit(const RootOfNode &) override
void visit(const ProductNode &node) override
void visit(const IntegralNode &node) override
void visit(const VariableNode &node) override
void visit(const TransformNode &node) override
std::set< std::string > names
void visit(const LimitNode &node) override
void visit(const SetBuilderNode &node) override
void visit(const QuantifierNode &node) override
void visit(const SummationNode &node) override
void visit(const ProductNode &node) override
detail::SymbolicNodePtr replacement_
void visit(const SetBuilderNode &node) override
const std::set< std::string > replacement_free_
void visit(const LimitNode &node) override
std::set< std::string > occupied_
FreeSubstitution(std::string target, detail::SymbolicNodePtr replacement, std::set< std::string > replacement_free, std::set< std::string > occupied, detail::RewriteBudget *budget)
void visit(const SummationNode &node) override
void visit(const TransformNode &node) override
void visit(const RootOfNode &) override
void visit(const VariableNode &node) override
void visit(const QuantifierNode &node) override
void visit(const IntegralNode &node) override
detail::SymbolicNodePtr rewrite_scoped(const detail::SymbolicNodePtr &original_body, std::string &binder, bool &changed)
void visit(const QuantifierNode &node) override
std::set< std::string > variables
bool is_bound(const std::string &name) const
void visit(const VariableNode &node) override
void visit(const LimitNode &node) override
void visit(const SummationNode &node) override
void visit(const TransformNode &node) override
void visit(const ProductNode &node) override
void visit_binder(const SymbolicNode &node)
void visit(const RootOfNode &) override
void visit(const IntegralNode &node) override
std::unordered_map< std::string_view, std::size_t > bound_
void visit(const SetBuilderNode &node) override
void visit(const SetBuilderNode &node) override
void visit(const SummationNode &node) override
void visit(const IntegralNode &node) override
void visit(const TransformNode &node) override
void visit(const QuantifierNode &node) override
void visit(const ProductNode &node) override
const std::string_view name_
void visit(const LimitNode &node) override
void visit_binder(const SymbolicNode &node)
const bool antiderivatives_
void visit(const VariableNode &node) override
FreeVariableFinder(std::string_view name, detail::RewriteBudget *budget=nullptr, bool antiderivatives=false)
void visit(const NumberNode &) override
virtual void visit_child(const SymbolicNodePtr &child)
void visit_children(const Range &children)
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
void set_result(SymbolicNodePtr result)
SymbolicNodePtr rewrite_child(const SymbolicNodePtr &child, bool &changed)
SymbolicNodePtr current() const noexcept
RewriteBudget * rewrite_budget() const noexcept
std::string fresh_name(const std::string &base, std::set< std::string > &occupied)
std::set< std::string > all_names(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget=nullptr)
Result< Polynomial< SymbolicPolyCoeff > > symbolic_to_poly_checked(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
bool is_imaginary_unit_name(const std::string &name)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::optional< BinderView > binder_view(const SymbolicNode &node)
const std::string & variable
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
bool integration_depends_on_variable(const SymbolicNodePtr &expression, const std::string &variable, RewriteBudget *budget=nullptr)
std::shared_ptr< const Node > make_node(Args &&... args)
std::optional< Rational > exact_rational_value(const NumberNode &number)
std::size_t std::size_t ComputationContext & context
std::set< std::string > all_variable_names(const SymbolicNodePtr &expression, RewriteBudget *budget=nullptr)
Result< std::optional< AffineForm > > recognize_affine(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
const std::string const LimitExprPtr & point
const std::string & variable
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
ExprResult integer(Integer)=delete
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
std::optional< int > exact_small_integer_node(const detail::SymbolicNodePtr &node, int min_value, int max_value)
const NumberDomainSet & domain
std::set< std::string > free_variables(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget)
const std::string const ExprPtr & value
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
ExprResult rational(const Rational &value)
detail::SymbolicNodePtr substitute_free(const detail::SymbolicNodePtr &expression, const std::string &variable, const detail::SymbolicNodePtr &replacement, detail::RewriteBudget *budget)