LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
normalization_numeric_powers.cpp
浏览该文件的文档.
2#include <cstdint>
3
4namespace LMCAS {
5namespace {
6std::shared_ptr<const NumberNode> reciprocal_exact_number(const NumberNode& number) {
7 if (const auto* integer = std::get_if<BigInt>(&number.value())) {
8 return detail::make_node<NumberNode>(Rational(BigInt(1), *integer));
9 }
10 if (const auto* rational = std::get_if<Rational>(&number.value())) {
11 if (!rational->get_numerator().is_zero()) {
13 Rational(rational->get_denominator(), rational->get_numerator()));
14 }
15 }
16 return nullptr;
17}
18
19std::shared_ptr<const NumberNode> small_exact_power(const NumberNode& base,
20 const BigInt& exponent) {
21 const auto count = exponent.abs().try_to_uint64();
22 if (const auto* integer = std::get_if<BigInt>(&base.value())) {
23 BigInt value(1);
24 for (std::uint64_t k = 0; k < *count; ++k) value = value * *integer;
26 }
27 if (const auto* rational = std::get_if<Rational>(&base.value())) {
28 Rational value(1);
29 for (std::uint64_t k = 0; k < *count; ++k) value = value * *rational;
31 }
32 return nullptr;
33}
34
35std::shared_ptr<const SymbolicNode> integer_numeric_power(
36 const std::shared_ptr<const NumberNode>& base, const BigInt& exponent) {
37 const bool small = exponent > BigInt(-64) && exponent < BigInt(64);
38 if (exponent == BigInt(-1)) {
39 return reciprocal_exact_number(*base);
40 }
41 if (exponent.is_zero()) {
42 return detail::make_node<NumberNode>(BigInt(1));
43 }
44 if (!small) {
45 return nullptr;
46 }
47 auto powered = small_exact_power(*base, exponent);
48 if (!powered) {
49 return nullptr;
50 }
51 if (exponent > BigInt(0)) {
52 return powered;
53 }
54 return reciprocal_exact_number(*powered);
55}
56
58 if (const auto* rational = std::get_if<Rational>(&exponent.value())) {
59 return *rational == Rational(1, 2);
60 }
61 return false;
62}
63
64std::shared_ptr<const SymbolicNode> extract_small_square_factor(
65 const BigInt& value, const BigInt& root, detail::RewriteBudget* budget) {
66 if (value <= BigInt(0) || value >= BigInt(1000000)) {
67 return nullptr;
68 }
69 for (BigInt factor = root; factor >= BigInt(2); factor -= BigInt(1)) {
70 const BigInt square = factor * factor;
71 if (!(value % square).is_zero()) {
72 continue;
73 }
74 if (budget) { budget->require_nodes(5); }
75 auto coefficient = detail::make_node<NumberNode>(factor);
76 auto radicand = detail::make_node<NumberNode>(value / square);
77 auto half = detail::make_node<NumberNode>(Rational(1, 2));
78 auto radical = detail::make_node<PowerNode>(radicand, half);
79 return SymbolicFactory::create_multiply({coefficient, radical}, budget);
80 }
81 return nullptr;
82}
83
84std::shared_ptr<const SymbolicNode> half_numeric_power(
85 const NumberNode& base, detail::RewriteBudget* budget) {
86 if (const auto* integer = std::get_if<BigInt>(&base.value())) {
87 if (*integer < BigInt(0)) {
88 return nullptr;
89 }
90 const BigInt root = integer->sqrt();
91 if (root * root == *integer) {
93 }
94 return extract_small_square_factor(*integer, root, budget);
95 }
96 if (auto root = normalization_exact_square_root(base)) {
97 return root;
98 }
99 return nullptr;
100}
101}
102
103std::shared_ptr<const NumberNode> normalization_exact_square_root(const NumberNode& number) {
104 if (const auto* integer = std::get_if<BigInt>(&number.value())) {
105 if (*integer < BigInt(0)) {
106 return nullptr;
107 }
108 const BigInt root = integer->sqrt();
109 if (root * root == *integer) {
111 }
112 return nullptr;
113 }
114 const auto* rational = std::get_if<Rational>(&number.value());
115 if (!rational || *rational < Rational(0)) {
116 return nullptr;
117 }
118 const BigInt numerator = rational->get_numerator().sqrt();
119 const BigInt denominator = rational->get_denominator().sqrt();
120 if (numerator * numerator != rational->get_numerator()) {
121 return nullptr;
122 }
123 if (denominator * denominator != rational->get_denominator()) {
124 return nullptr;
125 }
126 return detail::make_node<NumberNode>(Rational(numerator, denominator));
127}
128
129std::shared_ptr<const SymbolicNode> normalization_imaginary_power(
130 const BigInt& exponent, detail::RewriteBudget* budget) {
131 BigInt remainder = exponent % BigInt(4);
132 if (remainder.is_negative()) remainder += BigInt(4);
133 if (budget) { budget->require_nodes(3); }
134 if (remainder.is_zero()) {
135 return detail::make_node<NumberNode>(BigInt(1));
136 }
137 if (remainder == BigInt(2)) {
138 return detail::make_node<NumberNode>(BigInt(-1));
139 }
140 auto imaginary = detail::make_node<PowerNode>(
142 detail::make_node<NumberNode>(Rational(1, 2)));
143 if (remainder == BigInt(1)) {
144 return imaginary;
145 }
147 {detail::make_node<NumberNode>(BigInt(-1)), imaginary}, budget);
148}
149
150std::shared_ptr<const SymbolicNode> normalization_numeric_power(
151 const std::shared_ptr<const NumberNode>& base,
152 const std::shared_ptr<const NumberNode>& exponent, detail::RewriteBudget* budget) {
153 if (budget) { budget->require_nodes(1); }
154 BigInt integer;
156 if (auto value = integer_numeric_power(base, integer)) {
157 return value;
158 }
159 } else if (is_half_exponent(*exponent)) {
160 if (auto value = half_numeric_power(*base, budget)) {
161 return value;
162 }
163 }
164 const auto* rational = std::get_if<Rational>(&exponent->value());
165 if (!rational || !base->is_negative_one()) {
166 return nullptr;
167 }
168 if (rational->get_denominator() != BigInt(2)) {
169 return nullptr;
170 }
171 return normalization_imaginary_power(rational->get_numerator(), budget);
172}
173}
const std::variant< BigInt, Rational > & value() const noexcept
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
void require_nodes(std::size_t nodes) const
std::shared_ptr< const NumberNode > small_exact_power(const NumberNode &base, const BigInt &exponent)
std::shared_ptr< const SymbolicNode > half_numeric_power(const NumberNode &base, detail::RewriteBudget *budget)
std::shared_ptr< const SymbolicNode > integer_numeric_power(const std::shared_ptr< const NumberNode > &base, const BigInt &exponent)
std::shared_ptr< const NumberNode > reciprocal_exact_number(const NumberNode &number)
std::shared_ptr< const SymbolicNode > extract_small_square_factor(const BigInt &value, const BigInt &root, detail::RewriteBudget *budget)
std::shared_ptr< const Node > make_node(Args &&... args)
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
std::shared_ptr< const SymbolicNode > normalization_imaginary_power(const BigInt &exponent, detail::RewriteBudget *budget=nullptr)
std::shared_ptr< const NumberNode > normalization_exact_square_root(const NumberNode &number)
const ExprPtr & exponent
std::shared_ptr< const SymbolicNode > normalization_numeric_power(const std::shared_ptr< const NumberNode > &base, const std::shared_ptr< const NumberNode > &exponent, detail::RewriteBudget *budget=nullptr)
const std::string const ExprPtr & value
std::shared_ptr< const SymbolicNode > make_normalized_multiply_node(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, detail::RewriteBudget *budget=nullptr)
const ExprPtr & denominator
ExprResult rational(const Rational &value)