LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
complex_quadratic.cpp
浏览该文件的文档.
2
9
10#include <new>
11#include <optional>
12#include <utility>
13
14namespace LMCAS::detail {
15namespace {
16
17constexpr const char* kOperation = "solve_complex_quadratic";
18using Node = std::shared_ptr<const SymbolicNode>;
19using Coefficients = std::array<std::shared_ptr<SymbolicExpr>, 3>;
20
23}
24
25Node add(const Node& left, const Node& right) {
26 return SymbolicFactory::create_add({left, right});
27}
28
29Node multiply(const Node& left, const Node& right) {
31}
32
34 return multiply(integer(-1), value);
35}
36
37Node divide(const Node& numerator, const Node& denominator) {
39}
40
42 auto step = context.consume_steps(1, kOperation);
43 if (!step) {
44 return ExpressionResult::failure(step.error());
45 }
46 RewriteBudget budget(context, context.limits().max_recursion_depth,
47 context.limits().max_ast_nodes, kOperation);
49 std::optional<AssumptionFacts> facts;
50 if (context.assumptions()) facts.emplace(*context.assumptions());
51 NormalizationVisitor visitor(budget, facts ? static_cast<const FactsQuery&>(*facts)
53 value->accept(visitor);
54 auto result = visitor.get_result();
55 if (!result) {
57 "quadratic normalization returned null", kOperation);
58 }
59 budget.measure(result);
60 return make_expression_ptr(std::move(result));
61}
62
65 for (const auto& coefficient : input) {
66 auto step = context.consume_steps(1, kOperation);
67 if (!step) {
68 return Result<Coefficients>::failure(step.error());
69 }
70 if (!coefficient || !node(coefficient)) {
72 "quadratic coefficients must not be null", kOperation);
73 }
74 }
75 Coefficients result;
76 for (std::size_t i = 0; i < input.size(); ++i) {
77 auto simplified = normalize(node(input[i]), context);
78 if (!simplified) {
79 return Result<Coefficients>::failure(simplified.error());
80 }
81 result[i] = std::move(simplified.value());
82 }
83 return result;
84}
85
87 const AssumptionContext& facts,
89 auto step = context.consume_steps(4, kOperation);
90 if (!step) {
91 return step;
92 }
93 if (node(coefficients[0])->is_zero()) {
95 "quadratic leading coefficient is zero", kOperation);
96 }
97 AssumptionFacts adapter(facts);
98 for (const auto& coefficient : coefficients) {
99 auto real = query_real_value(node(coefficient), adapter, context);
100 if (!real) {
102 }
103 if (real.value() != Tribool::True) {
105 "quadratic coefficients must be provably real", kOperation);
106 }
107 }
108 auto nonzero = facts.is_nonzero_checked(*coefficients[0], context);
109 if (!nonzero) {
110 return Result<void>::failure(nonzero.error());
111 }
112 if (nonzero.value() == Tribool::False) {
114 "quadratic leading coefficient is zero", kOperation);
115 }
116 if (nonzero.value() != Tribool::True) {
118 "quadratic leading coefficient is not provably nonzero", kOperation);
119 }
120 return Result<void>::success();
121}
122
123Result<bool> negative_discriminant(const SymbolicExpr& delta,
124 const AssumptionContext& facts,
126 auto step = context.consume_steps(2, kOperation);
127 if (!step) {
128 return Result<bool>::failure(step.error());
129 }
130 auto nonnegative = facts.is_nonnegative_checked(delta, context);
131 if (!nonnegative) {
132 return Result<bool>::failure(nonnegative.error());
133 }
134 if (nonnegative.value() == Tribool::True) {
135 return false;
136 }
137 auto negative = facts.is_negative_checked(delta, context);
138 if (!negative) {
139 return Result<bool>::failure(negative.error());
140 }
141 if (negative.value() == Tribool::True) {
142 return true;
143 }
145 "quadratic discriminant sign is unknown", kOperation);
146}
147
149 const Node& real, const Node& imag, ComputationContext& context) {
150 auto real_part = normalize(real, context);
151 if (!real_part) {
152 return Result<QuadraticCartesianRoot>::failure(real_part.error());
153 }
154 auto imag_part = normalize(imag, context);
155 if (!imag_part) {
156 return Result<QuadraticCartesianRoot>::failure(imag_part.error());
157 }
158 return QuadraticCartesianRoot{std::move(real_part.value()), std::move(imag_part.value())};
159}
160
162 const Coefficients& coefficients, const Node& delta, bool negative,
164 const auto denominator = multiply(integer(2), node(coefficients[0]));
165 const auto minus_b = negate(node(coefficients[1]));
166 const auto radical = SymbolicFactory::create_power(
167 negative ? negate(delta) : delta, SymbolicFactory::create_number(Rational(1, 2)));
168 const auto real = divide(minus_b, denominator);
169 const auto imag = divide(radical, denominator);
170 auto first = normalized_root(
171 negative ? real : add(real, imag),
172 negative ? imag : integer(0), context);
173 if (!first) {
174 return Result<CartesianQuadraticRoots>::failure(first.error());
175 }
176 auto second = normalized_root(
177 negative ? real : add(real, negate(imag)),
178 negative ? negate(imag) : integer(0), context);
179 if (!second) {
180 return Result<CartesianQuadraticRoots>::failure(second.error());
181 }
182 return CartesianQuadraticRoots{std::move(first.value()), std::move(second.value())};
183}
184
189
191 return {add(left.real, right.real), add(left.imag, right.imag)};
192}
193
195 return {add(multiply(left.real, right.real), negate(multiply(left.imag, right.imag))),
196 add(multiply(left.real, right.imag), multiply(left.imag, right.real))};
197}
198
200 auto simplified = normalize(residual, context);
201 if (!simplified) {
202 return Result<void>::failure(simplified.error());
203 }
204 auto proof = check_zero_residual(simplified.value(), context);
205 if (!proof) {
206 return Result<void>::failure(proof.error());
207 }
208 if (!std::holds_alternative<ProvedZeroResidual>(proof.value())) {
210 "quadratic Cartesian residual could not be proved zero", kOperation);
211 }
212 return Result<void>::success();
213}
214
216 const QuadraticCartesianRoot& root,
218 auto step = context.consume_steps(16, kOperation);
219 if (!step) {
220 return step;
221 }
222 const auto zero = integer(0);
223 const CartesianNodes a{node(coefficients[0]), zero};
224 const CartesianNodes b{node(coefficients[1]), zero};
225 const CartesianNodes c{node(coefficients[2]), zero};
226 const CartesianNodes z{node(root.real), node(root.imag)};
227 const auto residual = cartesian_add(
229 auto real = prove_zero(residual.real, context);
230 if (!real) {
231 return real;
232 }
233 return prove_zero(residual.imag, context);
234}
235
237 const Coefficients& coefficients, const AssumptionContext& facts,
239 auto valid = prove_coefficients(coefficients, facts, context);
240 if (!valid) {
241 return Result<CartesianQuadraticRoots>::failure(valid.error());
242 }
243 const auto b = node(coefficients[1]);
244 auto delta = normalize(add(multiply(b, b), negate(multiply(integer(4),
245 multiply(node(coefficients[0]), node(coefficients[2]))))), context);
246 if (!delta) {
247 return Result<CartesianQuadraticRoots>::failure(delta.error());
248 }
249 auto negative = negative_discriminant(*delta.value(), facts, context);
250 if (!negative) {
251 return Result<CartesianQuadraticRoots>::failure(negative.error());
252 }
253 auto roots = construct_roots(coefficients, node(delta.value()), negative.value(), context);
254 if (!roots) {
255 return roots;
256 }
257 for (const auto& root : roots.value()) {
258 auto verified = verify_root(coefficients, root, context);
259 if (!verified) {
260 return Result<CartesianQuadraticRoots>::failure(verified.error());
261 }
262 }
263 return roots;
264}
265
266}
267
269 const std::shared_ptr<SymbolicExpr>& a,
270 const std::shared_ptr<SymbolicExpr>& b,
271 const std::shared_ptr<SymbolicExpr>& c,
273 try {
274 auto coefficients = normalize_coefficients({a, b, c}, context);
275 if (!coefficients) {
276 return Result<CartesianQuadraticRoots>::failure(coefficients.error());
277 }
278 if (context.assumptions()) {
279 return solve_real_quadratic(coefficients.value(), *context.assumptions(), context);
280 }
281 const AssumptionContext facts;
282 return solve_real_quadratic(coefficients.value(), facts, context);
283 } catch (const CasError& error) {
285 } catch (const std::bad_alloc&) {
287 "quadratic construction allocation failed", kOperation);
288 } catch (const std::exception& error) {
290 error.what(), kOperation);
291 }
292}
293
294}
AssumptionContext class with scoped push/pop management.
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
std::shared_ptr< const SymbolicNode > get_result() const
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_power(std::shared_ptr< const SymbolicNode > base, std::shared_ptr< const SymbolicNode > exponent)
创建幂运算节点,自动处理指数为 0/1 及底数为 0/1 的情况.
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
static std::shared_ptr< const SymbolicNode > create_number(const ::LMCAS::BigInt &v)
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
Result< Coefficients > normalize_coefficients(const Coefficients &input, ComputationContext &context)
Node divide(const Node &numerator, const Node &denominator)
Result< CartesianQuadraticRoots > solve_real_quadratic(const Coefficients &coefficients, const AssumptionContext &facts, ComputationContext &context)
Result< CartesianQuadraticRoots > construct_roots(const Coefficients &coefficients, const Node &delta, bool negative, ComputationContext &context)
ExpressionResult normalize(const Node &value, ComputationContext &context)
CartesianNodes cartesian_add(const CartesianNodes &left, const CartesianNodes &right)
Result< bool > negative_discriminant(const SymbolicExpr &delta, const AssumptionContext &facts, ComputationContext &context)
Result< void > prove_coefficients(const Coefficients &coefficients, const AssumptionContext &facts, ComputationContext &context)
Result< void > prove_zero(const Node &residual, ComputationContext &context)
Result< QuadraticCartesianRoot > normalized_root(const Node &real, const Node &imag, ComputationContext &context)
std::array< std::shared_ptr< SymbolicExpr >, 3 > Coefficients
CartesianNodes cartesian_multiply(const CartesianNodes &left, const CartesianNodes &right)
Result< void > verify_root(const Coefficients &coefficients, const QuadraticCartesianRoot &root, ComputationContext &context)
多元 Hensel 提升(单变量步)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::array< QuadraticCartesianRoot, 2 > CartesianQuadraticRoots
Result< CartesianQuadraticRoots > real_quadratic_roots_checked(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, ComputationContext &context)
const FactsQuery & no_facts() noexcept
RewriteBudget const FactsQuery & facts
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
const VectorField const VectorField & c
@ True
Property definitely holds
@ False
Property definitely does not hold
const MultiPoly & b
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
__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
ExprPtr imag
const ExprPtr & right
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
ResidualCheckResult check_zero_residual(const ExprPtr &residual, ComputationContext &context, const LMCAS::EqvOptions &options)
const std::string const ExprPtr & value
const ExprPtr & denominator
符号规范化访问器接口。
内部 AST 定义。